I've just read this tutorial about Rust and I've extracted some interesting 
bits:
http://doc.rust-lang.org/doc/tutorial.html

My comments are in inside [...].

--------------------

>From 3.9:

The compiler defines a few built-in syntax extensions. The most useful one is 
#fmt, a printf-style text formatting macro that is expanded at compile time.

std::io::println(#fmt("%s is %d", "the answer", 42));

#fmt supports most of the directives that printf supports, but will give you a 
compile-time error when the types of the directives don't match the types of 
the arguments.

[In D I hope we'll something like:  cwriteln!"%s is %d"("the answer", 42)  that 
tests the formatting string at compile-time, avoiding run-time errors.]

--------------------

>From 4.2:

A powerful application of pattern matching is destructuring, where you use the 
matching to get at the contents of data types. Remember that (float, float) is 
a tuple of two floats:

fn angle(vec: (float, float)) -> float {
    alt vec {
      (0f, y) if y < 0f { 1.5 * float::consts::pi }
      (0f, y) { 0.5 * float::consts::pi }
      (x, y) { float::atan(y / x) }
    }
}


[For D see http://d.puremagic.com/issues/show_bug.cgi?id=596  but it's simpler, 
no if guards]

--------------------

4.3 Destructuring let

To a limited extent, it is possible to use destructuring patterns when 
declaring a variable with let. For example, you can say this to extract the 
fields from a tuple:

let (a, b) = get_tuple_of_two_ints();

This will introduce two new variables, a and b, bound to the content of the 
tuple.

[There is a pull request for this in D.]

--------------------

5.1.3 Unique closures

Unique closures, written fn~ in analogy to the ~ pointer type (see next 
section), hold on to things that can safely be sent between processes. They 
copy the values they close over, much like boxed closures, but they also 'own' 
them—meaning no other code can access them. Unique closures mostly exist for 
spawning new tasks.

--------------------

>From 5.3:

To run such an iteration, you could do this:

for_rev([1, 2, 3], {|n| log(error, n); });

Making use of the shorthand where a final closure argument can be moved outside 
of the parentheses permits the following, which looks quite like a normal loop:

for_rev([1, 2, 3]) {|n|
    log(error, n);
}

[A similar simple syntax sugar was proposed for D too.]

--------------------

>From 6.6:

Rust supports several types of pointers. The simplest is the unsafe pointer, 
written *TYPE, which is a completely unchecked pointer type only used in unsafe 
code (and thus, in typical Rust code, very rarely). The safe pointer types are 
@TYPE for shared, reference-counted boxes, and ~TYPE, for uniquely-owned 
pointers.

All pointer types can be dereferenced with the * unary operator.

--------------------

>From 7.4:

Then there is the by-copy style, written +. This indicates that the function 
wants to take ownership of the argument value. If the caller does not use the 
argument after the call, it will be 'given' to the callee. Otherwise a copy 
will be made. This mode is mostly used for functions that construct data 
structures. The argument will end up being owned by the data structure, so if 
that can be done without a copy, that's a win.

type person = {name: str, address: str};
fn make_person(+name: str, +address: str) -> person {
    ret {name: name, address: address};
}

--------------------

9.7 Exporting

By default, a module exports everything that it defines. This can be restricted 
with export directives at the top of the module or file.

mod enc {
    export encrypt, decrypt;
    const super_secret_number: int = 10;
    fn encrypt(n: int) -> int { n + super_secret_number }
    fn decrypt(n: int) -> int { n - super_secret_number }
}

This defines a rock-solid encryption algorithm. Code outside of the module can 
refer to the enc::encrypt and enc::decrypt identifiers just fine, but it does 
not have access to enc::super_secret_number.

[In Haskell and Python there is something similar. In D you mark with "private" 
the global names of a module you don't want to export. But I think listing them 
all at the top of the module allows you to control them better.]

--------------------

13 Testing

The Rust language has a facility for testing built into the language. Tests can 
be interspersed with other code, and annotated with the #[test] attribute.

use std;

fn twice(x: int) -> int { x + x }

#[test]
fn test_twice() {
    let i = -100;
    while i < 100 {
        assert twice(i) == 2 * i;
        i += 1;
    }
}

When you compile the program normally, the test_twice function will not be 
included. To compile and run such tests, compile with the --test flag, and then 
run the result:

> rustc --test twice.rs
> ./twice
running 1 tests
test test_twice ... ok
result: ok. 1 passed; 0 failed; 0 ignored

Or, if we change the file to fail, for example by replacing x + x with x + 1:

running 1 tests
test test_twice ... FAILED
failures:
    test_twice
result: FAILED. 0 passed; 1 failed; 0 ignored


[D unittesting needs some improvement here.]

--------------------

Bye,
bearophile

Reply via email to