1 / 41

The D Programming Language

The D Programming Language. CS 4450. What is D?. A system programming language conceived in 1996 as a C++ replacement Combines the power of C++ with the usability of languages like Java, C# and Python If something works in C++, C# or Java, it probably works pretty much the same in D.

ivan
Download Presentation

The D Programming Language

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. The D Programming Language CS 4450

  2. What is D? • A system programming language conceived in 1996 as a C++ replacement • Combines the power of C++ with the usability of languages like Java, C# and Python • If something works in C++, C# or Java, it probably works pretty much the same in D

  3. “Often, programming teams will resort to a hybrid approach, where they will mix Python and C++, trying to get the productivity of Python and the performance of C++. The frequency of this approach indicates that there is a large unmet need in the programming language department.” “D intends to fill that need. It combines the ability to do low-level manipulation of the machine with the latest technologies in building reliable, maintainable, portable, high-level code. D has moved well ahead of any other language in its abilities to support and integrate multiple paradigms like imperative, OOP, and generic programming.” — Walter Bright, Co-designer of D

  4. D is like C++ • It supports static local variables • It supports pointers • but you almost never need them (we won’t) • It has templates • but they’re easier and more flexible than in C++ • it supports compile-time execution • It’s fast • compiles to native code • It supports operator overloading

  5. D is Like Java and C# • It supports garbage collection • the default, but you can opt-out • It supports explicit, user-defined interfaces • uses “:” for inheritance, like C# • It has inner classes, like Java and C# • It has delegates • but more powerful than in C# • It distinguishes reference and value types • It supports properties

  6. D is Like Python and FP Languages • It has modules and packages • like Python’s • It supports nested functions and closures • including anonymous functions • It has a pure FP subset • and the usual higher-order functions • reduce, map, filter, compose • supports lazy evaluation of function parameters

  7. D is for Real Programmers • It has software engineering support: • unit testing • contract programming • invariants, preconditions, postconditions • built-in constructs for exception-safetransactions • Supports concurrent programming • with thread-local storage • both lock and lockless programming • Can interoperate with C and C++

  8. D'iving In // hello.d import std.stdio; void main(string[] args) { if (args.length > 1) foreach (a; args[1..$]) writeln("Hello " ~ a); else writeln("Hello, Modern World"); } Chuck-Allisons-iMac-4:CCSC chuck$ dmd hello.d Chuck-Allisons-iMac-4:CCSC chuck$ ./hello Hello, Modern World Chuck-Allisons-iMac-4:CCSC chuck$ ./hello John Jane Hello John Hello Jane

  9. Primitive Data Types Type Meaning Default (.init) void no value n/a bool Boolean value false byte signed 8 bits 0 ubyte unsigned 8 bits 0 short signed 16 bits 0 ushort unsigned 16 bits 0 int signed 32 bits 0 uint unsigned 32 bits 0 long signed 64 bits 0 ulong unsigned 64 bits 0 float 32-bit floating-point float. nan double 64-bit floating-point double. nan real largest in hardware real. nan char unsigned 8-bit UTF-8 0xFF wchar unsigned 16-bit UTF-16 0xFFFF dchar unsigned 32-bit UTF-32 0x0000FFFF

  10. Literals and Type Inference • Uses the same suffixes as C/C++ • f, l, u, etc. • Uses the same prefixes • 0123, 0x1CF • Adds binary: 0b01001 • Type inference with auto: auto targetSalary = 15_000_000; auto sq = (double x) { return x*x; };

  11. Arrays • Static arrays • Similar to arrays in C/C++ • int a[3]; • int[3] a; // Same thing • Dynamic Arrays • Similar to vectors, ArrayLists, etc. • See staticarray.d • Initialization: • int[3] a = [1:2, 3]; // [0,2,3]

  12. Selected Array Operations • Indexing with [ ] • Concatenation with ~ • Copying with a.dup • Assignment with = • Length with .length • $ = .length in index expressions (a[2..$]) • m..n is an array slice (excludesn) • can assign to .length to resize dynamic arrays • Array-wise operations (mathematical vector operations) • See mergesort.d, vector.d

  13. Strings • Strings are dynamic arrays of immutable characters • alias immutable(char)[] string; • string  char (UTF-8) • wstring  wchar (UTF-16) • dstring  dchar (UTF-32) • foreach visits each character: • foreach (c; s) …

  14. Associative Arrays • A map (aka “dictionary”, “hash”, etc.) • Except it’s a built-in type (like dict in Python) • Uses array syntax: void main() { int[string] mymap = ["one":1, "two":2]; mymap["three"] = 3; foreach (k,v; mymap) writef("%s:%s ",k,v); } /* Output: three:3 one:1 two:2 */

  15. Word Count Program Output /* Abbreviated output from the Gettysburg Address: But,: 1 Four: 1 … who: 3 will: 1 work: 1 world: 1 years: 1 */

  16. A Word Count Program import std.stdio, std.array, std.file; void wc(string filename) { string[] words = split(cast(string) read(filename)); int[string] counts; foreach (word; words) ++counts[word]; foreach (w; counts.keys.sort) writefln("%s: %d", w, counts[w]); } void main(string[] args) { if (args.length == 2) wc(args[1]); }

  17. Tuples • Defined in std.typecons • Tuple!(type1,type2,..) • Helper function: • tuple(val1,val2,…) • Can use 0-based positionnumbers • Can also use field names • See tuple.d

  18. Data Qualifiers • For function parameters: • in | out | inout • ref • lazy • General declaration qualifiers: • const • immutable

  19. Lazy Parameters import std.stdio; void f(bool b, lazy void g) { if (b) { g(); } } void main() { f(false, writeln("executing g")); f(true, writeln("executing g")); } /* Output: executing g */

  20. Closures • Nested functions are returned as (dynamic) closures • aka “delegates” (a code-environment pair) • The referencing environment could be a function, class, or object • Escaped activation records are moved from the stack to the garbage-collected heap • Plain function pointers also supported: • int function(int) f; (vs. “int (*f)(int);” in C)

  21. Plain Function Pointers int f1(int n) {return n+1;} int f2(int n) {return n+2;} int f3(int n) {return n+3;} void main() { auto funs = [&f1, &f2, &f3]; foreach (f; funs) writeln(f(1)); } /* Output: 2 3 4 */

  22. Higher-Level Functions and Closures import std.stdio; bool delegate(int) gtn(int n) { bool execute(int m) { return m > n; } return &execute; } void main() { auto g5 = gtn(5); // Returns a ">5" delegate writeln(g5(1)); // false writeln(g5(6)); // true }

  23. Lambda Expressions auto gtn(int n) { return delegate bool(int m) {return m > n;}; } // Preferred: auto gtn(int n) { return (int m) {return m > n;}; }

  24. An Object Calling Environment void main() {     class A { int fun() { return 42; } }     A a = new A;     auto dg = &a.fun; // A “bound method”     writeln(dg()); // 42 }

  25. Parametric PolymorphismCompile-time Parameters auto gtn(T)(T n) { return (T m) {return m > n;}; } void main() { auto g5 = gtn(5); writeln(g5(1)); writeln(g5(6)); auto g5s = gtn("baz"); writeln(g5s("bar")); writeln(g5s("foo")); }

  26. Compile-Time Constraints import std.stdio, std.traits; auto gtn(T)(T n) if (isNumeric!T) { return (T m) {return m > n;}; } void main() { auto g5 = gtn!int(5); writeln(g5(1)); writeln(g5(6)); auto g5s = gtn!string("baz"); // Error writeln(g5s("bar")); writeln(g5s("foo")); }

  27. Compile-Time Function Evaluation // ctfe.d: Compile-time function execution import std.stdio, std.conv; int square(int i) { return i * i; } void main() { static int n = square(3); // compile time writefln(text(n)); writefln(text(square(4))); // runtime }

  28. Pure FunctionsFor Referential Transparency import std.stdio; import std.conv; pure ulong fib(uint n) { if (n == 0 || n == 1) return n; ulong a = 1, b = 1; foreach (i; 2..n) { auto t = b; b += a; a = t; } return b; } void main(string[] args) { if (args.length > 1) writeln(fib(to!(uint)(args[1]))); }

  29. Selected Higher-Level Functions int[] nums = [1,2,3,4,5]; auto squarelist(int[] list) { // 1 4 9 16 25 return map!("a*a")(list); } auto sqsum2(int[] list) { // 55 return reduce!("a + b*b")(0,list); // (list) } auto evens(int[] list) { // 2 4 return filter!("a % 2 == 0")(list); } alias compose!("a/3.0","a*a","a+1.0") comp; writeln(comp(2.0)); // 3 = (2+1)^2 / 3 alias pipe!(div3,sq,pls1) pip; // fns in scope writeln(pip(2.0)); // 1.4444 = (2/3)^2+1

  30. std.functional.memoize • Memoization is a technique where a cache of input-output pairs is kept for function calls • Avoids recomputing function values • See fib.d

  31. Variable-length Argument Lists • Use “…” in the parameter definition • Homogeneous • use “…” in the runtime parameter list • passes a dynamic array • Heterogeneous • use “…” in the compile-time parameter list • passes a tuple • See varargs.d

  32. An Unsafe Function void g() { risky_op1(); // May acquire resources… risky_op2(); risky_op3(); writeln("g succeeded"); } Assume further that these functions must run to completion or not at all.

  33. An Unsavory Solution void g() { risky_op1(); try { risky_op2(); } catch (Exception x) { undo_risky_op1(); // Back-out op1 throw x; // Rethrow exception } try { risky_op3(); writeln("g succeeded"); } catch (Exception x) { // Back-out op1 and op2 in reverse order undo_risky_op2(); undo_risky_op1(); throw x; } }

  34. D’s scope StatementOptions: exit | success | failure void g() { risky_op1(); scope(failure) undo_risky_op1(); risky_op2(); scope(failure) undo_risky_op2(); risky_op3(); writeln("g succeeded"); }

  35. Contract Programming ExampleAlso illustrates value types, operator overloading, and unit testing import std.math; // For abs() struct Rational { private int num = 0; private int den = 1; // Local helper function static int gcd(int m, int n) { return n == 0 ? abs(m) : gcd(abs(n), abs(m)%abs(n)); } // Class invariant invariant() { assert(den > 0 && gcd(num, den) == 1); }

  36. Contract Programming Example(continued) // Constructor this(int n, int d = 1) // Constructor precondition in { assert(d != 0); } body { num = n; den = d; auto div = gcd(num, den); if (den < 0) div = -div; num /= div; den /= div; }

  37. Contract Programming Example(concluded) // ("if" form evaluated at compile time) Rational opBinary(string op)(Rational r) if (op == "+”) { return Rational(num*r.den + den*r.num, den*r.den); } } unittest { // Compile with –unittest option auto r1 = Rational(1,2), r2 = Rational(3,4), r3 = r1 + r2; assert(r3.num == 5 && r3.den == 4); } void main(){}

  38. Variant Types • Sometimes you want to hold any type • hopefully not too often! • Variant can hold any type • You can only get out what was last put in • see variant.d • Bounded, discriminated unions with Algebraic • like ML unions • see variant2.d

  39. Threads • A thread is a path of execution inside a running program (process) • A thread is launched on a function basis • Using the std.concurrency.spawn • See concur1.d

  40. Message Passing A paradigm for thread-to-thread communication Threads send/receive data to/from each other Less problematic (and less flexible) than sharing data via mutexes See concur1,2,3.d

  41. Infinite Streams in D • Threads and Message Passing naturally support streams • See stream.d

More Related