Differences

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

Link to this comparison view

dss:laboratoare:06 [2019/07/01 14:00]
eduard.staniloiu [static if]
dss:laboratoare:06 [2019/07/01 15:29] (current)
eduard.staniloiu [Exercises]
Line 110: Line 110:
  
 ==== Mixins ==== ==== Mixins ====
 +
 +Mixins are for mixing in generated code into the source code. The mixed in code
 +may be generated as a template instance or a string .
 +
 +=== Template mixins ===
 +
 +Template mixins insert instantiations of templates into the code by the **mixin** keyword:
 +<code d>
 +mixin a_template!(template_parameters)
 +</​code>​
 +
 +As we will see in the example below, the **mixin** keyword is used in the definitions of template mixins as well.
 +
 +The instantiation of the template for the specific set of template parameters is inserted into the source code right where the **mixin** keyword appears.
 +
 +For example, let's have a template that defines both an array of edges and a pair of functions that operate on those edges:
 +
 +<code d>
 +mixin template EdgeArrayFeature(T,​ size_t count) {
 +  T[count] edges;
 +  void setEdge(size_t index, T edge) {
 +    edges[index] = edge;
 +  }
 +  void printEdges() {
 +    writeln("​The edges:"​);​
 +    foreach (i, edge; edges) {
 +      writef("​%s:​%s ", i, edge);
 +    }
 +    writeln();
 +  }
 +}
 +</​code>​
 +
 +That template leaves the type and number of array elements flexible.
 +For example, the **mixin** below can insert the two-element //**int** array// and the two functions that are generated by the template right inside a **struct** definition:
 +
 +<code d>
 +struct Line {
 +  mixin EdgeArrayFeature!(int,​ 2);
 +}
 +</​code>​
 +
 +As a result, **Line** ends up defining a member array and two member functions:
 +<code d>
 +import std.stdio;
 +
 +void main() {
 +  auto line = Line();
 +  line.setEdge(0,​ 100);
 +  line.setEdge(1,​ 200);
 +  line.printEdges();​
 +}
 +</​code>​
 +
 +=== String mixins ===
 +
 +Another powerful feature of D is being able to insert code as string as long as that string is known at compile time. The syntax of string mixins requires the use of parentheses:​
 +<code d>
 +mixin (compile_time_generated_string)
 +</​code>​
 +
 +For example, the //hello world// program can be written with a **mixin** as well:
 +<code d>
 +import std.stdio;
 +
 +void main() {
 +  mixin (`writeln("​Hello,​ World!"​);​`);​
 +}
 +</​code>​
 +
 +Obviously, there is no need for mixins in these examples, as the strings could have been written as code as well.
 +
 +The power of string mixins comes from the fact that the code can be generated at compile time.
 +
 +A common use case of string mixins is **Operator Overloading**:​
 +<code d>
 +struct A {
 +  int x;
 +  ​
 +  ref A opOpAssign(string op)(ref A rhs)
 +  if (op == "​+"​ || op == "​-"​)
 +  {
 +    mixin("​this.x"​ ~ op ~ "= rhs.x;"​);​
 +  }
 +}
 +
 +void main() {
 +  A a1 = A(20);
 +  A a2 = A(22);
 +  ​
 +  a1 += a2;
 +  writeln(a1);​ // -> 42
 +  a1 -= a2;
 +  writeln(a1);​ // -> 20
 +</​code>​
 +
 +Another example is represented by string predicates. Let's consider the following function template that takes an array of numbers
 +and returns another array that consists of the elements that satisfy a specific condition:
 +
 +<code d>
 +int[] filter(string predicate)(int[] numbers) {
 +  int[] result;
 +  foreach (number; numbers) {
 +    if (mixin (predicate)) {
 +      result ~= number;
 +    }
 +  }
 +  return result;
 +}
 +</​code>​
 +
 +That function template takes the filtering condition as its template parameter and inserts that condition directly into an if statement as is.
 +
 +For that condition to choose numbers that are e.g. less than 7, the if condition should look like the following code:
 +<code d>
 +if (number < 7) {
 +</​code>​
 +
 +The users of the **filter()** template can provide the condition as a string:
 +<code d>
 +int[] numbers = [ 1, 8, 6, -2, 10 ];
 +int[] chosen = filter!"​number < 7"​(numbers);​
 +</​code>​
 +
 +Importantly,​ the name used in the template parameter must match the name of the variable used in the implementation of filter() . So, the template must document what that name should be and the users must use that name.
 +
 +Phobos uses names consisting of single letters like a, b, n, etc.
 +
 +<​note>​
 +Specifying predicates as strings was used more commonly before the lambda syntax was added to D. Although string predicates as in this example are still used in Phobos, the **=>** lambda syntax may be more suitable in most cases.
 +</​note>​
 +
 +==== Exercises ====
 +
 +=== 1. checkedint ===
 +
 +We want to define a **struct CheckedInt** that defines facilities for efficient checking of integral operations against overflow, casting with loss of precision, unexpected change of sign, etc. **CheckedInt** must work with both built-in integral types and other **CheckedInt**s.
 +
 +CheckedInt offers encapsulated integral wrappers that do all checking internally and have configurable behavior upon erroneous results. For example, **CheckedInt!int** is a type that behaves like int but aborts execution immediately whenever involved in an operation that produces the arithmetically wrong result. ​
 +
 +The declaration should look something like
 +<code d>
 +struct Checked(T, Hook)
 +</​code>​
 +
 +In order to work with built-in types, you need to define: opAssign, opBinary, opBinaryRight,​ opCast, opCmp, opEquals, opOpAssign, opUnary.
 +
 +CheckedInt has customizable behavior with the help of a second type parameter, Hook. Depending on the Hook type, core operations on the underlying integral may be verified for overflow or completely redefined. Implement the following predefined hooks:
 +  - **Abort** : fails every incorrect operation with a message to std.stdio. stderr followed by a call to assert(0). It is the default second parameter, i.e. Checked!short is the same as Checked!(short,​ Abort).
 +  - **Throw** : fails every incorrect operation by throwing an exception. ​
 +  - **Warn**: prints incorrect operations to std.stdio.stderr but otherwise preserves the built-in behavior. ​
 +
 +
 +
 +
dss/laboratoare/06.1561978817.txt.gz ยท Last modified: 2019/07/01 14:00 by eduard.staniloiu
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