Differences

This shows you the differences between two versions of the page.

Link to this comparison view

dss:laboratoare:04 [2019/06/21 13:48]
razvan.nitu1305
dss:laboratoare:04 [2021/07/12 18:58] (current)
razvan.nitu1305 [5. Ranges]
Line 218: Line 218:
 } }
 </​code>​ </​code>​
 +
 +==== alias ====
 +
 +The **alias** keyword assigns aliases to existing names. **alias** is useful in 3 types of situations:
 +
 +**1.** Shortening a long name
 +
 +<code D>
 +Stack!(Point!double) randomPoints(size_t count)
 +{
 +    auto points = new Stack!(Point!double);​
 +// ...
 +}
 +</​code>​
 +
 +Having to type **Stack!(Point!double)** explicitly in multiple places in the
 +program has a number of drawbacks:
 +
 +  * Longer names can make the code harder to read.
 +  * It is unnecessary to be reminded at every point that the type is the **Stack** data structure that contains objects of the double instantiations of the **Point** struct template.
 +  * If the requirements of the program change and e.g. **double** needs to be changed to **real** , this change must be carried out in multiple places.
 +
 +These drawbacks can be eliminated by giving a new name to **Stack!(Point!double)** :
 +
 +<code D>
 +alias Points = Stack!(Point!double);​
 +// ...
 +Points randomPoints(size_t count)
 +{
 +    auto points = new Points;
 +// ...
 +}
 +</​code>​
 +
 +**2.** Design Flexibility
 +
 +For flexibility,​ even fundamental types like int can have aliases:
 +
 +<code D>
 +alias CustomerNumber = int;
 +alias CompanyName = string;
 +// ...
 +struct Customer
 +{
 +    CustomerNumber number;
 +    CompanyName company;
 +// ...
 +}
 +</​code>​
 +
 +**3.** Revealing hidden names of superclass
 +
 +When the same name appears both in the superclass and in the subclass, the
 +matching names that are in the superclass are hidden. Even a single name in the
 +subclass is sufficient to hide all of the names of the superclass that match that
 +name:
 +
 +<code D>
 +class Super
 +{
 +    void foo(int x) { /* ... */ }
 +}
 +class Sub : Super
 +{
 +    void foo() {/* ... */ }
 +}
 +void main()
 +{
 +    auto object = new Sub;
 +    object.foo(42); ​           // ---> Compilation error
 +}
 +</​code>​
 +
 +Since the argument is 42, an int value, one might expect that the Super.foo
 +function that takes an int would be called for that use. However, even though
 +their parameter lists are different, Sub.foo hides Super.foo and causes a
 +compilation error. The compiler disregards Super.foo altogether and reports
 +that Sub.foo cannot be called by an int :
 +
 +<code bash>
 +Error: function deneme.Sub.foo () is not callable
 +using argument types (int)
 +</​code>​
 +
 +Note that this is not the same as overriding a function of the superclass. For that,
 +the function signatures would be the same and the function would be overridden
 +by the **override** keyword.
 +
 +Here, not overriding, but a language feature called **name hiding** is in effect. If
 +there were not name hiding, functions that happen to have the same name **foo**
 +that are added to or removed from these classes might silently change the
 +function that would get called. Name hiding prevents such surprises. It is a
 +feature of other OOP languages as well.
 +**alias** can reveal the hidden names when desired:
 +
 +<code D>
 +class Super
 +{
 +    void foo(int x) { /* ... */ }
 +}
 +
 +class Sub : Super
 +{
 +    void foo() { /* ... */ }
 +    alias foo = Super.foo;
 +}
 +</​code>​
 +
 +==== Alias This ====
 +
 +<code D>
 +struct S
 +{
 +    int x;
 +    alias x this;
 +}
 +
 +int foo(int i) { return i * 2; }
 +
 +void test()
 +{
 +    S s;
 +    s.x = 7;
 +    int i = -s;  // i == -7
 +    i = s + 8;   // i == 15
 +    i = s + s;   // i == 14
 +    i = 9 + s;   // i == 16
 +    i = foo(s); ​ // implicit conversion to int
 +}
 +</​code>​
 +
 +An **alias this** declaration names a member to subtype. A class or struct can be implicitly converted to the **alias this** member. If the member is a class or struct, undefined lookups will be forwarded to the **alias this** member.
 +
 +==== Pure Functions ====
 +
 +Pure functions are functions that cannot directly access global or static mutable state. pure guarantees that a pure function call won't access or modify any implicit state in the program. Unlike other functional programming languages, D's pure functions allow modification of the caller state through their mutable parameters.
 +
 +<code D>
 +pure int foo(int[] arr) { arr[] += 1; return arr.length; }
 +int[] a = [1, 2, 3];
 +foo(a);
 +assert(a == [2, 3, 4]);
 +</​code>​
 +
 +A pure function accepting parameters with mutable indirections offers what's called "weak purity"​ because it can change program state transitively through its arguments. A pure function that has no parameter with mutable indirections is called "​strongly pure" and fulfills the purity definition in traditional functional languages. Weakly pure functions are useful as reusable building blocks for strongly pure functions.
 +
 +To prevent mutation, D offers the immutable type qualifier. If all of a pure function'​s parameters are immutable or copied values without any indirections (e.g. int), the type system guarantees no side effects.
 +
 +<code D>
 +struct S { double x; }
 +pure int foo(immutable(int)[] arr, int num, S val)
 +{
 +    //arr[num] = 1; // compile error
 +    num = 2;        // has no side effect to the caller side
 +    val.x = 3.14;   // ditto
 +    return arr.length;
 +}
 +</​code>​
 +
 +==== Nothrow Functions ====
 +
 +Nothrow functions can only throw exceptions derived from class Error (not from class Exception):
 +
 +<code D>
 +int add(int lhs, int rhs) nothrow
 +{
 +    writeln("​adding"​); ​   // โ† compilation ERROR
 +    return lhs + rhs;
 +}
 +</​code>​
 +
 +The compiler rejects the code because add() violates the no-throw guarantee:
 +
 +<code bash>
 +Error: function '​deneme.add'​ is nothrow yet may throw
 +</​code>​
 +
 +This is because writeln is not (and cannot be) a nothrow function.
 +
 +The compiler can infer that a function can never emit an exception. The following implementation of add() is nothrow because it is obvious to the compiler that the try-catch block prevents any exception from escaping the function:
 +
 +<code D>
 +int add(int lhs, int rhs) nothrow
 +{
 +    int result;
 +
 +    try
 +    {
 +        writeln("​adding"​); ​   // โ† compiles
 +        result = lhs + rhs;
 +
 +    } catch (Exception error) ​  // catches all exceptions
 +    {   
 +        // ...
 +    }
 +
 +    return result;
 +}
 +</​code>​
 +
 +As mentioned above, nothrow does not include exceptions that are under the Error hierarchy. For example, although accessing an element of an array with [] can throw RangeError, the following function can still be defined as nothrow:
 +
 +<code D>
 +int foo(int[] arr, size_t i) nothrow
 +{
 +    return 10 * arr[i];
 +}
 +</​code>​
 +
 +==== Nogc Functions ====
 +
 +D is a garbage collected language. Many data structures and algorithms in most D programs take advantage of dynamic memory blocks that are managed by the garbage collector (GC). Such memory blocks are reclaimed again by the GC by an algorithm called garbage collection.
 +
 +Some commonly used D operations take advantage of the GC as well. For example, elements of arrays live on dynamic memory blocks:
 +
 +<code D>
 +// A function that takes advantage of the GC indirectly
 +int[] append(int[] slice)
 +{
 +    slice ~= 42;
 +    return slice;
 +}
 +</​code>​
 +
 +If the slice does not have sufficient capacity, the ~= operator above allocates a new memory block from the GC.
 +
 +Although the GC is a significant convenience for data structures and algorithms, memory allocation and garbage collection are costly operations that make the execution of some programs noticeably slow.
 +
 +**@nogc** means that a function cannot use the GC directly or indirectly:
 +
 +<code D>
 +void foo() @nogc
 +{
 +    // ...
 +}
 +</​code>​
 +
 +The compiler guarantees that a @nogc function does not involve GC operations. For example, the following function cannot call append() above, which does not provide the @nogc guarantee:
 +
 +<code D>
 +void foo() @nogc
 +{
 +    int[] slice;
 +    // ...
 +    append(slice); ​   // โ† compilation ERROR
 +}
 +</​code>​
 +
 +<code bash>
 +Error: @nogc function '​deneme.foo'​ cannot call non-@nogc function
 +'​deneme.append'​
 +</​code>​
 +
 +For an extensive list of operations forbidden in **@nogc** code, check this [[https://​dlang.org/​spec/​function.html#​nogc-functions|link]]
 +
 +==== Ranges ====
 +
 +Any object which fulfills the following interface is called a **range** (or more specific **InputRange**) and is thus a type that can be iterated over:
 +
 +<code D>
 +    interface InputRange(E)
 +    {
 +        bool empty();
 +        E front();
 +        void popFront();
 +    }
 +</​code>​
 +
 +Check this [[https://​tour.dlang.org/​tour/​en/​basics/​ranges|link]] for an example of a Fibonaci range implementation.
 +
 +Besides the dumbest form of range, the **InputRange**,​ the are other forms of ranges:
 +
 +  * **ForwardRange** is an **InputRange** and additionally requires the **save** method that saves the state of the range.
 +  * **BidirectionalRange** is a **ForwardRange** and additionally requires the **back** and **popBack** methods.
 +  * **RandomAccessRange** is a **BidirectionalRange** and additionally requires the **[]** operator (and another property depending whether the range is finite or infinite)
 +
 +For more informations on ranges, you can read the outstanding [[http://​ddili.org/​ders/​d.en/​ranges.html|description]] in Ali's book.
 +
 +===== Exercises =====
 +
 +The lab can be found at this [[https://​github.com/​RazvanN7/​D-Summer-School/​tree/​master/​lab-04|link]].
 +
 +==== 1. Complex numbers ====
 +
 +Implement a struct that will emulate a [[https://​en.wikipedia.org/​wiki/​Complex_number|complex number]]. The operations that need to be implemented on complex numbers are: assignment, addition, subtraction,​ multiply and division. Write a unittest to assure the validity of the implementation.
 +
 +<​note>​
 +What happens if you comment the assignment operator?
 +</​note>​
 +
 +==== 2. Alias ====
 +
 +Navigate to the ''​2-alias''​ directory. Inspect the two source files. Compile de code:
 +
 +<code bash>
 +dmd main.d func.d
 +</​code>​
 +
 +What happens? Why? Before invoking function **fun**, add the line:
 +
 +<code D>
 +alias fun = func.fun;
 +</​code>​
 +
 +What happens? Why?
 +
 +==== 3. Nullable ====
 +
 +Implement a [[https://​dlang.org/​library/​std/​typecons/​nullable.html#​2|Nullable]] object. In D, there are certain types that cannot be null (such as int, struct objects etc.), also there are algorithms that work only for types that can be in the null state; for those algorithms to work with non-nullable types, an abstraction is considered in the form of a Nullable object.
 +
 +  * Implement the Nullable(T) struct by having a templated field which is the value and a boolean that keeps track whether the value is null or not; the Nullable object is considered null if the field holds the **.init** value
 +  * Implement the methods: ​
 +  - get: returns the value of the object if not null; if null, halts execution raising an assert error with the appropriate message;
 +  - opAssign: a Nullable!T object can be assigned a value of type T;
 +  - a constructor that takes a value of type T;
 +       
 +What is the problem with this implementation?​
 +
 +==== 4. Alias this ====
 +
 +Solve the problem of the previous **Nullable!T** implementation by forwarding unknown operations to the T object contained. Test the new implementation by adding instances of **Nullable** with int, struct and class.
 +
 +==== 5. Ranges ====
 +
 +Implement a stack that respects the range interface.
 +
 +  - Implement the stack as an input range (you may use builtin arrays as the underlying data structure);
 +  - Improve the stack by adding support for forward range methods;
 +  - Improve the stack by adding support for bidirectional range methods;
 +  - Improve the stack by adding support for random access range methods;
 +
 +To test your implementation you can use these [[https://​dlang.org/​phobos/​std_range_primitives.html|range primitives]]
dss/laboratoare/04.1561114113.txt.gz ยท Last modified: 2019/06/21 13:48 by razvan.nitu1305
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0