This shows you the differences between two versions of the page.
|
dss:laboratoare:03 [2019/06/13 14:50] razvan.nitu1305 |
dss:laboratoare:03 [2019/06/21 13:10] (current) razvan.nitu1305 |
||
|---|---|---|---|
| Line 1: | Line 1: | ||
| - | ===== Lab03: Memory Safety ===== | + | ===== Lab 03: Memory Safety ===== |
| During this lab you will learn about the memory safety mechanisms that are available in D. | During this lab you will learn about the memory safety mechanisms that are available in D. | ||
| Line 52: | Line 52: | ||
| test.d(10): Error: cannot take address of local a in @safe function main | test.d(10): Error: cannot take address of local a in @safe function main | ||
| </code> | </code> | ||
| + | |||
| + | <note tip> | ||
| + | |||
| + | For templated functions, the **@safe** attribute is inferred after the function has been generated | ||
| + | with the provided instantiation types. This means that a templated function can generate a **@safe** | ||
| + | function for one type and an un-**@safe** function for a different type. | ||
| + | |||
| + | </note> | ||
| ==== @trusted ==== | ==== @trusted ==== | ||
| Line 155: | Line 163: | ||
| 3. **immutable** data is implicitly convertible to **const**, but not to **mutable**. | 3. **immutable** data is implicitly convertible to **const**, but not to **mutable**. | ||
| + | === shared === | ||
| + | |||
| + | Unlike most other programming languages, data is not automatically shared in D; | ||
| + | data is thread-local by default. Although module-level variables may give the | ||
| + | impression of being accessible by all threads, each thread actually gets its own | ||
| + | copy: | ||
| + | |||
| + | <code D> | ||
| + | import std.stdio; | ||
| + | import std.concurrency; | ||
| + | import core.thread; | ||
| + | |||
| + | int variable; | ||
| + | void printInfo(string message) | ||
| + | { | ||
| + | writefln("%s: %s (@%s)", message, variable, &variable); | ||
| + | } | ||
| + | |||
| + | void worker() | ||
| + | { | ||
| + | variable = 42; | ||
| + | printInfo("Before the worker is terminated"); | ||
| + | } | ||
| + | |||
| + | void main() | ||
| + | { | ||
| + | spawn(&worker); | ||
| + | thread_joinAll(); | ||
| + | printInfo("After the worker is terminated"); | ||
| + | } | ||
| + | </code> | ||
| + | |||
| + | the variable that is modified inside **worker()** is not the same variable that is seen | ||
| + | by **main()**. Mutable variables that need to be shared must be defined with the shared | ||
| + | keyword: | ||
| + | |||
| + | <code D> | ||
| + | shared int variable; | ||
| + | </code> | ||
| + | |||
| + | On the other hand, since **immutable** variables cannot be modified, there is no | ||
| + | problem with sharing them directly. For that reason, **immutable** implies **shared**. | ||
| + | |||
| + | ===== Exercises ===== | ||
| + | |||
| + | The exercises for ''lab-03'' are located in this [[https://github.com/RazvanN7/D-Summer-School/tree/master/lab-03|repo]]. | ||
| + | |||
| + | ==== 1. Qualifiers ==== | ||
| + | |||
| + | Navigate to the ''1-qualifiers'' directory. Read and understand the source file ''qualifiers.d''. Explain the working and the failing cases. | ||
| + | |||
| + | ==== 2. Qualified functions ==== | ||
| + | |||
| + | Navigate to the ''2-qualfuncs'' directory. Inspect the source file ''qualfuncs.d''. Should this code compile or not? Why? | ||
| + | |||
| + | * Add ''immutable'' at the end of the **foo** function signature. | ||
| + | <code D> | ||
| + | void foo() immutable | ||
| + | </code> | ||
| + | * What happens? How can this code be fixed? Ask the [[http://ocw.cs.pub.ro/courses/dss?&#team|lab rats]] for guidance. | ||
| + | |||
| + | ==== 3. Const ==== | ||
| + | |||
| + | Navigate to the ''3-const'' directory. Inspect the source file ''const.d''. Compile and run the code. Explain the results. | ||
| + | |||
| + | ==== 4. Array sort ==== | ||
| + | |||
| + | Implement a generic sorting algorithm for dynamic arrays. | ||
| + | |||
| + | * The arrays can be immutable/const/mutable. | ||
| + | * The array element type can be any type that is ordering comparable. | ||
| + | * The qualifier (mutable/const/immutabe) applies to both the array and the elements. | ||
| + | * You must use template constraints and/or static ifs. | ||
| + | * Recommendation: use 2 template overloads (one for mutable and one for const/immutable); the mutable version does in-place sorting, the const/immutable version creates a new array and returns it. | ||
| + | |||
| + | ==== 5. @safe ==== | ||
| + | |||
| + | Navigate to the ''5-safe'' directory. Inspect the source file. Compile and run the code. | ||
| + | |||
| + | - What does the code do? Why is it useful to take the address of a parameter? | ||
| + | - Add the **@safe** attribute to the **main** function. What happens? | ||
| + | - Add **@safe** to the **func** and **gun** functions. Analyze the error messages. | ||
| + | - How can we get rid of the first error message? | ||
| + | - What about the second error message? | ||
| + | |||
| + | ==== 6. @trusted ==== | ||
| + | |||
| + | Navigate to the ''6-trusted'' directory. Inspect the source file. Compile and run the code. | ||
| + | |||
| + | - Is this code safe? Why? | ||
| + | - Apply **@safe** to the **main** function. What happens? Why? | ||
| + | - Move the **read** line in a new function, **safeRead**, that will be marked as **@trusted**. | ||
| + | |||
| + | <note hint> | ||
| + | **@trusted** disables all the compiler checks for safety inside **@safe** functions. Be very careful when using it. With great power comes great responsibility. | ||
| + | </note> | ||
| + | |||
| + | ==== 7. Template attribute inference ==== | ||
| + | |||
| + | Navigate to the ''7-template-inference'' directory. Inspect the source file. Compile and run the code. | ||
| + | - Add the **@safe** attribute to the **main** function. How do you explain the result? Why isn't the compiler complaining for the second invocation of func? | ||