Archivi Categorie: Rust

Rust – il linguaggio – 45

elibarzilay

Continuo, oggi qui: /usr/local/share/doc/rust/html/book/testing.html.

Testing

Bella la citazione di Dijkstra (la trovate là); ci sarebbe anche da citare Wirth ma dovrei googlare (o recuperare un manuale che chissà dov’è finito).
Let’s talk about how to test Rust code. What we will not be talking about is the right way to test Rust code. There are many schools of thought regarding the right and wrong way to write tests. All of these approaches use the same basic tools, and so we’ll show you the syntax for using them.

L’attributo test

At its simplest, a test in Rust is a function that’s annotated with the test attribute. Let’s make a new project with Cargo called adder:

rs45-0

Cargo will automatically generate a simple test when you make a new project. Here’s the contents of src/lib.rs:

rs45-1

Note the #[test]. This attribute indicates that this is a test function. It currently has no body. That’s good enough to pass! We can run the tests with cargo test:

rs45-2

Cargo compiled and ran our tests. There are two sets of output here: one for the test we wrote, and another for documentation tests. We’ll talk about those later. For now, see this line:

test it_works ... ok

Note the it_works. This comes from the name of our function:

fn it_works() {

We also get a summary line:

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured

So why does our do-nothing test pass? Any test which doesn’t panic! passes, and any test that does panic! fails. Let’s make our test fail:

#[test]
fn it_works() {
    assert!(false);
}

rs45-3

Rust indicates that our test failed:

test it_works ... FAILED

And that’s reflected in the summary line:

test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured

We also get a non-zero status code. We can use $? on OS X and Linux:

rs45-4

On Windows, if you’re using cmd: echo %ERRORLEVEL%.

This is useful if you want to integrate cargo test into other tooling.

We can invert our test’s failure with another attribute: should_panic:

#[test]
#[should_panic]
fn it_works() {
    assert!(false);
}

rs45-5

Rust provides another macro, assert_eq!, that compares two arguments for equality, non riporto il test.

should_panic tests can be fragile, as it’s hard to guarantee that the test didn’t fail for an unexpected reason. To help with this, an optional expected parameter can be added to the should_panic attribute. The test harness will make sure that the failure message contains the provided text. A safer version of the example above would be:

#[test]
#[should_panic(expected = "assertion failed")]
fn it_works() {
    assert_eq!("Hello", "world");
}

That’s all there is to the basics! Let’s write one ‘real’ test:

pub fn add_two(a: i32) -> i32 {
    a + 2
}

#[test]
fn it_works() {
    assert_eq!(4, add_two(2));
}

This is a very common use of assert_eq!: call some function with some known arguments and compare it to the expected output.

Sarà che sono vecchio ma preferisco non automatizzare troppo; io uso dei print nelle funzioni che voglio verificare.

L’attributo ignore

Sometimes a few specific tests can be very time-consuming to execute. These can be disabled by default by using the ignore attribute:

#[test]
fn it_works() {
    assert_eq!(4, add_two(2));
}

#[test]
#[ignore]
fn expensive_test() {
    // code that takes an hour to run
}

Now we run our tests and see that it_works is run, but expensive_test is not.

The expensive tests can be run explicitly using cargo test -- --ignored.
The --ignored argument is an argument to the test binary, and not to Cargo, which is why the command is cargo test -- --ignored.

Il modulo tests

There is one way in which our existing example is not idiomatic: it’s missing the tests module. The idiomatic way of writing our example looks like this: –No non copio/provo/riporto. Se del caso è là.

Lo stesso vale per la directory tests e la documentazione che viene automaticamente prodotta. Troppo specifico per il mio esame :mrgreen:

Rust – il linguaggio – 44

mwl_00_2-2

Continuo con Rust, oggi inizio la sezione Effective Rust [/usr/local/share/doc/rust/html/book/effective-rust.html], sono qui: /usr/local/share/doc/rust/html/book/the-stack-and-the-heap.html.

Lo stack e l’heap

Rust è un linguaggio di sistema, come il C. È quindi importante sapere come gestisce a memoria, con uno stack e un heap.

Non copio, tanto è tutto là, chiaro. Solo qualche cenno, altrimenti non riesco a fare il post 😉

Gestione della memoria

These two terms are about memory management. The stack and the heap are abstractions that help you determine when to allocate and deallocate memory.

Here’s a high-level comparison:

  • The stack is very fast, and is where memory is allocated in Rust by default. But the allocation is local to a function call, and is limited in size.
  • The heap, on the other hand, is slower, and is explicitly allocated by your program. But it’s effectively unlimited in size, and is globally accessible.

Lo stack

Let’s talk about this Rust program:

fn main() {
    let x = 42;
}

This program has one variable binding, x. This memory needs to be allocated from somewhere. Rust ‘stack allocates’ by default, which means that basic values ‘go on the stack’. What does that mean?

Well, when a function gets called, some memory gets allocated for all of its local variables and some other information. This is called a ‘stack frame’, and for the purpose of this tutorial, we’re going to ignore the extra information and just consider the local variables we’re allocating. So in this case, when main() is run, we’ll allocate a single 32-bit integer for our stack frame. This is automatically handled for you, as you can see; we didn’t have to write any special Rust code or anything.

When the function exits, its stack frame gets deallocated. This happens automatically as well.

Se poi il programma non è così semplice ci saranno altre variabili, p.es.:

fn foo() {
    let y = 5;
    let z = 100;
}

fn main() {
    let x = 42;
    foo();
}

This program has three variables total: two in foo(), one in main(). Just as before, when main() is called, a single integer is allocated for its stack frame. But before we can show what happens when foo() is called, we need to visualize what’s going on with memory. Your operating system presents a view of memory to your program that’s pretty simple: a huge list of addresses, from 0 to a large number, representing how much RAM your computer has.
Non continuo, le variabili vengono impilate (ehi! stack = pila), dai lo sappiamo (o è là). Salto pure tutto lo spiegone dell’heap [/usr/local/share/doc/rust/html/book/the-stack-and-the-heap.html#the-heap].
Anche perché non credo di aver davvero l’esigenza di gestire condizioni simili; anche con il C++ (il C non credo si usi normalmente) non è che ci si preoccupi più del necessario. Ma –aspetta che combinazione…

Cosa fanno gli altri linguaggi?

Most languages with a garbage collector heap-allocate by default. This means that every value is boxed. There are a number of reasons why this is done, but they’re out of scope for this tutorial. There are some possible optimizations that don’t make it true 100% of the time, too. Rather than relying on the stack and Drop to clean up memory, the garbage collector deals with the heap instead.

Cosa usare?

So if the stack is faster and easier to manage, why do we need the heap? A big reason is that Stack-allocation alone means you only have LIFO semantics for reclaiming storage. Heap-allocation is strictly more general, allowing storage to be taken from and returned to the pool in arbitrary order, but at a complexity cost.

Generally, you should prefer stack allocation, and so, Rust stack-allocates by default. The LIFO model of the stack is simpler, at a fundamental level. This has two big impacts: runtime efficiency and semantic impact.

Efficienza a runtime

Managing the memory for the stack is trivial: The machine just increments or decrements a single value, the so-called “stack pointer”. Managing memory for the heap is non-trivial: heap-allocated memory is freed at arbitrary points, and each block of heap-allocated memory can be of arbitrary size, the memory manager must generally work much harder to identify memory for reuse.

If you’d like to dive into this topic in greater detail, see Dynamic storage allocation: A survey and critical review, is a great introduction.

Impatto semantico

Stack-allocation impacts the Rust language itself, and thus the developer’s mental model. The LIFO semantics is what drives how the Rust language handles automatic memory management. Even the deallocation of a uniquely-owned heap-allocated box can be driven by the stack-based LIFO semantics, as discussed throughout this chapter. The flexibility (i.e. expressiveness) of non LIFO-semantics means that in general the compiler cannot automatically infer at compile-time where memory should be freed; it has to rely on dynamic protocols, potentially from outside the language itself, to drive deallocation (reference counting, as used by Rc<T> and Arc<T>, is one example of this).

When taken to the extreme, the increased expressive power of heap allocation comes at the cost of either significant runtime support (e.g. in the form of a garbage collector) or significant programmer effort (in the form of explicit memory management calls that require verification not provided by the Rust compiler).

Ho rimuginato sull’opportunità di pubblicare questo post; è fuori da quello che m’interessa, troppo da sistemista. Alla fine l’ho lasciato, ma se la sezione del manuale continua così cambio, salto, ometto, seleziono.
Vedrò. Prossimamente :mrgreen:

Rust – il linguaggio – 43

12316

Oggi qui: /usr/local/share/doc/rust/html/book/unsafe.html, proseguendo da qui.

unsafe

Rust’s main draw is its powerful static guarantees about behavior. But safety checks are conservative by nature: there are some programs that are actually safe, but the compiler is not able to verify this is true. To write these kinds of programs, we need to tell the compiler to relax its restrictions a bit. For this, Rust has a keyword, unsafe. Code using unsafe has less restrictions than normal code does.

Let’s go over the syntax, and then we’ll talk semantics. unsafe is used in four contexts. The first one is to mark a function as unsafe:

unsafe fn danger_will_robinson() {
    // scary stuff
}

All functions called from FFI must be marked as unsafe, for example. The second use of unsafe is an unsafe block:

unsafe {
    // scary stuff
}

The third is for unsafe traits:

unsafe trait Scary { }

And the fourth is for implementing one of those traits:

unsafe impl Scary for i32 {}

It’s important to be able to explicitly delineate code that may have bugs that cause big problems. If a Rust program segfaults, you can be sure it’s somewhere in the sections marked unsafe.

Cosa significa ‘safe’?

Safe, in the context of Rust, means ‘doesn’t do anything unsafe’. It’s also important to know that there are certain behaviors that are probably not desirable in your code, but are expressly not unsafe:

  • Deadlocks
  • Leaks of memory or other resources
  • Exiting without calling destructors
  • Integer overflow

Rust cannot prevent all kinds of software problems. Buggy code can and will be written in Rust. These things aren’t great, but they don’t qualify as unsafe specifically.

In addition, the following are all undefined behaviors in Rust, and must be avoided, even when writing unsafe code. Non copio tutto l’elenco di operazioni che sono poi quelle prevedibili 😕 o meglio che ogni programmatore dovrebbe conoscere; tanto è tutto qui: /usr/local/share/doc/rust/html/book/unsafe.html#what-does-safe-mean.

Superpoteri di unsafe

In both unsafe functions and unsafe blocks, Rust will let you do three things that you normally can not do. Just three. Here they are:

  • Access or update a static mutable variable.
  • Dereference a raw pointer.
  • Call unsafe functions. This is the most powerful ability.

That’s it. It’s important that unsafe does not, for example, ‘turn off the borrow checker’. Adding unsafe to some random Rust code doesn’t change its semantics, it won’t just start accepting anything. But it will let you write things that do break some of the rules.

You will also encounter the unsafe keyword when writing bindings to foreign (non-Rust) interfaces. You’re encouraged to write a safe, native Rust interface around the methods provided by the library.

Let’s go over the basic three abilities listed, in order.

Accedere o aggiornare uno static mut

Rust has a feature called ‘static mut’ which allows for mutable global state. Doing so can cause a data race, and as such is inherently not safe. For more details, see the static [/usr/local/share/doc/rust/html/book/const-and-static.html#static] section of the book.

Dereferenziare un raw pointer

Raw pointers let you do arbitrary pointer arithmetic, and can cause a number of different memory safety and security issues. In some senses, the ability to dereference an arbitrary pointer is one of the most dangerous things you can do. For more on raw pointers, see their section of the book [/usr/local/share/doc/rust/html/book/raw-pointers.html].

Chiamate a funzioni unsafe

This last ability works with both aspects of unsafe: you can only call functions marked unsafe from inside an unsafe block.

This ability is powerful and varied. Rust exposes some compiler intrinsics [/usr/local/share/doc/rust/html/book/intrinsics.html] as unsafe functions, and some unsafe functions bypass safety checks, trading safety for speed.

[E]ven though you can do arbitrary things in unsafe blocks and functions doesn’t mean you should. The compiler will act as though you’re upholding its invariants, so be careful!

E adesso…

Con questo post ho concluso la quarta parte del manuale di Rust, Syntax and Semantics. La quinta, Effective Rust entra nel dettaglio su come scrivere good Rust code, via una serie di tutorials quasi indipendenti. Prossimamente… 😆 Forse… 😉
:mrgreen:

Rust – il linguaggio – 42

troll-freesmall

Continuando ecco un capitolo nuovo: /usr/local/share/doc/rust/html/book/raw-pointers.html.

Raw Pointers

Sì, al solito non so tradurre ma credo che anche da noi si dica così.
Rust has a number of different smart pointer types in its standard library, but there are two types that are extra-special. Much of Rust’s safety comes from compile-time checks, but raw pointers don’t have such guarantees, and are unsafe to use.

*const T and *mut T are called ‘raw pointers’ in Rust. Sometimes, when writing certain kinds of libraries, you’ll need to get around Rust’s safety guarantees for some reason. In this case, you can use raw pointers to implement your library, while exposing a safe interface for your users. For example, * pointers are allowed to alias, allowing them to be used to write shared-ownership types, and even thread-safe shared memory types (the Rc<T> and Arc<T> types are both implemented entirely in Rust).

Here are some things to remember about raw pointers that are different than other pointer types. They:

  • are not guaranteed to point to valid memory and are not even guaranteed to be non-null (unlike both Box and &);
  • do not have any automatic clean-up, unlike Box, and so require manual resource management;
  • are plain-old-data, that is, they don’t move ownership, again unlike Box, hence the Rust compiler cannot protect against bugs like use-after-free;
  • lack any form of lifetimes, unlike &, and so the compiler cannot reason about dangling pointers; and
  • have no guarantees about aliasing or mutability other than mutation not being allowed directly through a *const T.

Generalità

Creating a raw pointer is perfectly safe:

let x = 5;
let raw = &x as *const i32;

let mut y = 10;
let raw_mut = &mut y as *mut i32;

However, dereferencing one is not. This won’t work:

fn main() {
    let x = 5;
    let raw = &x as *const i32;
    
    println!("raw points at {}", *raw);
}

rs42-0

When you dereference a raw pointer, you’re taking responsibility that it’s not pointing somewhere that would be incorrect. As such, you need unsafe:

fn main() {
    let x = 5;
    let raw = &x as *const i32;
    
    let points_at = unsafe { *raw };
    
    println!("raw points at {}", points_at);
}

rs42-1

For more operations on raw pointers, see their API documentation [/usr/local/share/doc/rust/html/std/primitive.pointer.html].

FFI

Solo per me che alle volte la memoria… FFI = Foreign Function Interface.
Raw pointers are useful for FFI: Rust’s *const T and *mut T are similar to C’s const T* and T*, respectively. For more about this use, consult the FFI chapter [/usr/local/share/doc/rust/html/book/ffi.html].

References e raw pointers

At runtime, a raw pointer * and a reference pointing to the same piece of data have an identical representation. In fact, an &T reference will implicitly coerce to an *const T raw pointer in safe code and similarly for the mut variants (both coercions can be performed explicitly with, respectively, value as *const T and value as *mut T).

Going the opposite direction, from *const to a reference &, is not safe. A &T is always valid, and so, at a minimum, the raw pointer *const T has to point to a valid instance of type T. Furthermore, the resulting pointer must satisfy the aliasing and mutability laws of references. The compiler assumes these properties are true for any references, no matter how they are created, and so any conversion from raw pointers is asserting that they hold. The programmer must guarantee this.

The recommended method for the conversion is:

fn main() {
    // explicit cast
    let i: u32 = 1;
    let p_imm: *const u32 = &i as *const u32;
    
    // implicit coercion
    let mut m: u32 = 2;
    let p_mut: *mut u32 = &mut m;
    
    unsafe {
        let ref_imm: &u32 = &*p_imm;
        let ref_mut: &mut u32 = &mut *p_mut;
        println!("{} {}", ref_imm, ref_mut);
    }
}

rs42-2

The &*x dereferencing style is preferred to using a transmute. The latter is far more powerful than necessary, and the more restricted operation is harder to use incorrectly; for example, it requires that x is a pointer (unlike transmute).

:mrgreen:

Rust – il linguaggio – 41

Cdg

Sempre sul debug, da qui oggi qui: /usr/local/share/doc/rust/html/book/macros.html#the-variable-crate.

La variabile $crate

A further difficulty occurs when a macro is used in multiple crates. Say that mylib defines

pub fn increment(x: u32) -> u32 {
    x + 1
}

#[macro_export]
macro_rules! inc_a {
    ($x:expr) => ( ::increment($x) )
}

#[macro_export]
macro_rules! inc_b {
    ($x:expr) => ( ::mylib::increment($x) )
}

inc_a only works within mylib, while inc_b only works outside the library. Furthermore, inc_b will break if the user imports mylib under another name.

Rust does not (yet) have a hygiene system for crate references, but it does provide a simple workaround for this problem. Within a macro imported from a crate named foo, the special macro variable $crate will expand to ::foo. By contrast, when a macro is defined and then used in the same crate, $crate will expand to nothing. This means we can write

#[macro_export]
macro_rules! inc {
    ($x:expr) => ( $crate::increment($x) )
}

to define a single macro that works both inside and outside our library. The function name will expand to either ::increment or ::mylib::increment.

To keep this system simple and correct, #[macro_use] extern crate ... may only appear at the root of your crate, not inside mod. This ensures that $crate is a single identifier.

The deep end

The introductory chapter mentioned recursive macros, but it did not give the full story. Recursive macros are useful for another reason: Each recursive invocation gives you another opportunity to pattern-match the macro’s arguments.

As an extreme example, it is possible, though hardly advisable, to implement the Bitwise Cyclic Tag automaton within Rust’s macro system.

macro_rules! bct {

    // cmd 0:  d ... => ...
    (0, $($ps:tt),* ; $_d:tt)
        => (bct!($($ps),*, 0 ; ));
    (0, $($ps:tt),* ; $_d:tt, $($ds:tt),*)
        => (bct!($($ps),*, 0 ; $($ds),*));

    // cmd 1p:  1 ... => 1 ... p
    (1, $p:tt, $($ps:tt),* ; 1)
        => (bct!($($ps),*, 1, $p ; 1, $p));
    (1, $p:tt, $($ps:tt),* ; 1, $($ds:tt),*)
        => (bct!($($ps),*, 1, $p ; 1, $($ds),*, $p));

    // cmd 1p:  0 ... => 0 ...
    (1, $p:tt, $($ps:tt),* ; $($ds:tt),*)
        => (bct!($($ps),*, 1, $p ; $($ds),*));

    // halt on empty data string
    ( $($ps:tt),* ; )
        => (());
}

Mettiamola così: capito poco 😦
A essere interamente onesto: capito niente, nada, zilch 😦
Da approfondire. Uh! ne parla Stack Overflow.
Non è per niente semplice; copio la seconda risposta.

fn main() {
    // "Bitwise Cyclic Tag" automation through macros
    macro_rules! bct {
        // cmd 0:  0 ... => ...
        (0, $($program:tt),* ; $_head:tt)
            => (pbct!($($program),*, 0 ; ));
        (0, $($program:tt),* ; $_head:tt, $($tail:tt),*)
            => (pbct!($($program),*, 0 ; $($tail),*));

        // cmd 1x:  1 ... => 1 ... x
        (1, $x:tt, $($program:tt),* ; 1)
            => (pbct!($($program),*, 1, $x ; 1, $x));
        (1, $x:tt, $($program:tt),* ; 1, $($tail:tt),*)
            => (pbct!($($program),*, 1, $x ; 1, $($tail),*, $x));

        // cmd 1x:  0 ... => 0 ...
        (1, $x:tt, $($program:tt),* ; $($tail:tt),*)
            => (pbct!($($program),*, 1, $x ; $($tail),*));

        // halt on empty data string
        ( $($program:tt),* ; )
            => (());
    }

    macro_rules! println_bct {
        () =>
            (println!(""));
        (;) =>
            (println!(":"));

        ($d:tt) =>
            (println!("{}", stringify!($d)));
        ($d:tt, $($data:tt),*) => {
            print!("{}", stringify!($d));
            println_bct!($($data),*);
        };
        ( ; $($data:tt),*) => {
            print!(":");
            println_bct!($($data),*);
        };

        ($x:tt ; $($data:tt),*) => {
            print!("{}", stringify!($x));
            println_bct!( ; $($data),*);
        };
        ($x:tt, $($program:tt),* ; $($data:tt),*) => {
            print!("{}", stringify!($x));
            println_bct!($($program),* ; $($data),*);
        };
    }

    macro_rules! pbct {
        ($($program:tt),* ; $($data:tt),*) => {
            println_bct!($($program),* ; $($data),*);
            bct!($($program),* ; $($data),*);
        };
    }

    pbct!(0, 0, 1, 1, 1, 0, 0, 0 ; 1, 0, 1);

    // This one causes the compiler to hit recursion limits, heh
    // pbct!(0, 0, 1, 1, 1, 1, 1, 0 ; 1, 0, 1);
}

rs41-13

Le macros più comuni

Here are some common macros you’ll see in Rust code.

panic!
This macro causes the current thread to panic. You can give it a message to panic with:

fn main() {
    panic!("oh no!");
}

rs41-14
vec!
The vec! macro is used throughout the book, so you’ve probably seen it already. It creates Vec<T>s with ease:

fn main() {
    let v = vec![1, 2, 3, 4, 5];
    println!("{}", v[1]);
}

rs41-15

It also lets you make vectors with repeating values. For example, a hundred zeroes:

fn main() {
    let v = vec![0; 100];
    println!("{}", v[42]);    
}

rs41-16
assert! e assert_eq!
These two macros are used in tests. assert! takes a boolean. assert_eq! takes two values and checks them for equality. true passes, false panic!s. Like this:

fn main() {
    // A-ok!
    
    assert!(true);
    assert_eq!(5, 3 + 2);
    
    // nope :(
    
    assert!(5 < 3);
    assert_eq!(5, 3);
}

rs41-17

try!
try! is used for error handling. It takes something that can return a Result<T, E>, and gives T if it’s a Ok<T>, and returns with the Err(E) if it’s that. Like this:

use std::fs::File;

fn foo() -> std::io::Result {
    let f = try!(File::create("foo.txt"));

    Ok(())
}

This is cleaner than doing this:

use std::fs::File;

fn foo() -> std::io::Result {
    let f = File::create("foo.txt");

    let f = match f {
        Ok(t) => t,
        Err(e) => return Err(e),
    };

    Ok(())
}

unreachable!
This macro is used when you think some code should never execute:

fn main() {
    if false {
        unreachable!();
    }
    println!("OK!");
}

rs41-18

Sometimes, the compiler may make you have a different branch that you know will never, ever run. In these cases, use this macro, so that if you end up wrong, you’ll get a panic! about it.

fn main() {
    let x: Option = None;
    
    match x {
        Some(_) => unreachable!(),
        None => println!("I know x is None!"),
    }
}

rs41-19
unimplemented!
The unimplemented! macro can be used when you’re trying to get your functions to typecheck, and don’t want to worry about writing out the body of the function. One example of this situation is implementing a trait with multiple required methods, where you want to tackle one at a time. Define the others as unimplemented! until you’re ready to write them.

Procedural macros

If Rust’s macro system can’t do what you need, you may want to write a compiler plugin [/usr/local/share/doc/rust/html/book/compiler-plugins.html] instead. Compared to macro_rules! macros, this is significantly more work, the interfaces are much less stable, and bugs can be much harder to track down. In exchange you get the flexibility of running arbitrary Rust code within the compiler. Syntax extension plugins are sometimes called ‘procedural macros’ for this reason.

😀 OK, le macros sono da sempre ardue, il debug pure, ma ora si cambia argomento 😀
:mrgreen:

Rust – il linguaggio – 40

12096619

Ancora macro, continuo da qui e oggi sono qui: /usr/local/share/doc/rust/html/book/macros.html#recursive-macros.

Macros ricorsive

A macro’s expansion can include more macro invocations, including invocations of the very same macro being expanded. These recursive macros are useful for processing tree-structured input, as illustrated by this (simplistic) HTML shorthand:

#![allow(unused_must_use)]
macro_rules! write_html {
    ($w:expr, ) => (());

    ($w:expr, $e:tt) => (write!($w, "{}", $e));

    ($w:expr, $tag:ident [ $($inner:tt)* ] $($rest:tt)*) => {{
        writeln!($w, "<{}>", stringify!($tag));
        write_html!($w, $($inner)*);
        write!($w, "", stringify!($tag));
        write_html!($w, $($rest)*);
    }};
}

fn main() {
  // FIXME(#21826)
    use std::fmt::Write;
    let mut out = String::new();

    write_html!(&mut out,
        html[
            head[title["Macros guide"]]
            body[h1["Macros are the best!"]]
        ]);

    println!("{}", out);
}

rs40-11

Ho fatto una piccola modifica con grande effetto: sostituito il primo write! con writeln! 😀

Debug del codice delle macros

To see the results of expanding macros, run rustc --pretty expanded. The output represents a whole crate, so you can also feed it back in to rustc, which will sometimes produce better error messages than the original compilation. Note that the --pretty expanded output may have a different meaning if multiple variables of the same name (but different syntax contexts) are in play in the same scope. In this case --pretty expanded, hygiene will tell you about the syntax contexts.

rs40-12

Questa è solo la parte iniziale dell’output che poi continua con righe molto indentate, eccone un pezzettino:

#![feature(prelude_import)]
#![no_std]
#![allow(unused_must_use)]
#[prelude_import]
use std::prelude::v1::*;
#[macro_use]
extern crate std as std;



fn main() {
    // FIXME(#21826)
    use std::fmt::Write;
    let mut out = String::new();
    {



        &mut out.write_fmt(::std::fmt::Arguments::new_v1({
                                                             static __STATIC_FMTSTR:
                                                                    &'static [&'static str]
                                                                    =
                                                                 &["<", ">\n"];
                                                             __STATIC_FMTSTR
                                                         },
                                                         &match (&"html",) {
                                                              (__arg0,) =>
                                                              [::std::fmt::ArgumentV1::new(__arg0,
                                                                                           ::std::fmt::Display::fmt)],
                                                          }));
        {
            &mut out.write_fmt(::std::fmt::Arguments::new_v1({
                                                                 static __STATIC_FMTSTR:
                                                                        &'static [&'static str]

Paura? 😉

rustc provides two syntax extensions that help with macro debugging. For now, they are unstable and require feature gates.

  • log_syntax!(...) will print its arguments to standard output, at compile time, and “expand” to nothing.
  • trace_macros!(true) will enable a compiler message every time a macro is expanded. Use trace_macros!(false) later in expansion to turn it off.

Requisiti sintattici

Even when Rust code contains un-expanded macros, Non copio il paragrafo, troppo specifico. Se ricordo bene dallo scorso millennio il debug è una specializzazione (o una punizione) 😉

Visibilità e import/export delle macros

Macros are expanded at an early stage in compilation, before name resolution. One downside is that scoping works differently for macros, compared to other constructs in the language.

Definition and expansion of macros both happen in a single depth-first, lexical-order traversal of a crate’s source. So a macro defined at module scope is visible to any subsequent code in the same module, which includes the body of any subsequent child mod items.

A macro defined within the body of a single fn, or anywhere else not at module scope, is visible only within that item.

If a module has the macro_use attribute, its macros are also visible in its parent module after the child’s mod item. If the parent also has macro_use then the macros will be visible in the grandparent after the parent’s mod item, and so forth.

The macro_use attribute can also appear on extern crate. In this context it controls which macros are loaded from the external crate, e.g.

#[macro_use(foo, bar)]
extern crate baz;

If the attribute is given simply as #[macro_use], all macros are loaded. If there is no #[macro_use] attribute then no macros are loaded. Only macros defined with the #[macro_export] attribute may be loaded.

To load a crate’s macros without linking it into the output, use #[no_link] as well.

An example:

macro_rules! m1 { () => (()) }

// visible here: m1

mod foo {
    // visible here: m1

    #[macro_export]
    macro_rules! m2 { () => (()) }

    // visible here: m1, m2
}

// visible here: m1

macro_rules! m3 { () => (()) }

// visible here: m1, m3

#[macro_use]
mod bar {
    // visible here: m1, m3

    macro_rules! m4 { () => (()) }

    // visible here: m1, m3, m4
}

// visible here: m1, m3, m4
fn main() { }

When this library is loaded with #[macro_use] extern crate, only m2 will be imported.

The Rust Reference has a listing of macro-related attributes [/usr/local/share/doc/rust/html/reference.html#macro-related-attributes].

😦 dai, ci siamo quasi 😉

:mrgreen:

Rust – il linguaggio – 39

bb

Continuo con le macros, oggi qui: /usr/local/share/doc/rust/html/book/macros.html#expansion.

Espansione

The right-hand side of a macro rule is ordinary Rust syntax, for the most part. But we can splice in bits of syntax captured by the matcher. From the original example:

$(
    temp_vec.push($x);
)*

Each matched expression $x will produce a single push statement in the macro expansion. The repetition in the expansion proceeds in “lockstep” with repetition in the matcher (more on this in a moment).

Because $x was already declared as matching an expression, we don’t repeat :expr on the right-hand side. Also, we don’t include a separating comma as part of the repetition operator. Instead, we have a terminating semicolon within the repeated block.

Another detail: the vec! macro has two pairs of braces on the right-hand side. They are often combined like so:

macro_rules! foo {
    () => {{
        ...
    }}
}

The outer braces are part of the syntax of macro_rules!. In fact, you can use () or [] instead. They simply delimit the right-hand side as a whole.

The inner braces are part of the expanded syntax. Remember, the vec! macro is used in an expression context. To write an expression with multiple statements, including let-bindings, we use a block. If your macro expands to a single expression, you don’t need this extra layer of braces.

Note that we never declared that the macro produces an expression. In fact, this is not determined until we use the macro as an expression. With care, you can write a macro whose expansion works in several contexts. For example, shorthand for a data type could be valid as either an expression or a pattern.

Mmmmm, 🙄 le macro, come al solito, sono –come dire– ecco 🙄
E poi manca un esempio completo 😦

Repetition

Non traduco, non so se si usa.
The repetition operator follows two principal rules:

  • $(...)* walks through one “layer” of repetitions, for all of the $names it contains, in lockstep, and
  • each $name must be under at least as many $(...)*s as it was matched against. If it is under more, it’ll be duplicated, as appropriate.

This baroque macro illustrates the duplication of variables from outer repetition levels.

macro_rules! o_O {
    (
        $(
            $x:expr; [ $( $y:expr ),* ]
        );*
    ) => {
        &[ $($( $x + $y ),*),* ]
    }
}

fn main() {
    let a: &[i32]
        = o_O!(10; [1, 2, 3];
               20; [4, 5, 6]);

    let res = a == [11, 12, 13, 24, 25, 26];
    println!("{}", res);
}

rs39-5

That’s most of the matcher syntax. These examples use $(...)*, which is a “zero or more” match. Alternatively you can write $(...)+ for a “one or more” match. Both forms optionally include a separator, which can be any token except + or *.

This system is based on Macro-by-Example. È un’intro alle macros, in Lisp (generico ma quasi-Scheme), da leggere.

Igiene

Some languages implement macros using simple text substitution, [uh! come quello che pensavo io, vedi nota iniziale del post precedente] which leads to various problems. For example, this C program prints 13 instead of the expected 25.

#define FIVE_TIMES(x) 5 * x

int main() {
    printf("%d\n", FIVE_TIMES(2 + 3));
    return 0;
}

After expansion we have 5 * 2 + 3, and multiplication has greater precedence than addition. If you’ve used C macros a lot, you probably know the standard idioms for avoiding this problem, as well as five or six others. In Rust, we don’t have to worry about it.

macro_rules! five_times {
    ($x:expr) => (5 * $x);
}

fn main() {
    println!("{}", five_times!(2 + 3));
}

rs39-6

The metavariable $x is parsed as a single expression node, and keeps its place in the syntax tree even after substitution.

Another common problem in macro systems is ‘variable capture’. Here’s a C macro, using a GNU C extension to emulate Rust’s expression blocks.

#define LOG(msg) ({ \
    int state = get_log_state(); \
    if (state > 0) { \
        printf("log(%d): %s\n", state, msg); \
    } \
})

Here’s a simple use case that goes terribly wrong:

const char *state = "reticulating splines";
LOG(state)

This expands to

const char *state = "reticulating splines";
int state = get_log_state();
if (state > 0) {
    printf("log(%d): %s\n", state, state);
}

The second variable named state shadows the first one. This is a problem because the print statement should refer to both of them.

The equivalent Rust macro has the desired behavior.

fn get_log_state() -> i32 { 3 }
macro_rules! log {
    ($msg:expr) => {{
        let state: i32 = get_log_state();
        if state > 0 {
            println!("log({}): {}", state, $msg);
        }
    }};
}

fn main() {
    let state: &str = "reticulating splines";
    log!(state);
}

rs39-7

This works because Rust has a hygienic macro system. Each macro expansion happens in a distinct ‘syntax context’, and each variable is tagged with the syntax context where it was introduced. It’s as though the variable state inside main is painted a different “color” from the variable state inside the macro, and therefore they don’t conflict.

This also restricts the ability of macros to introduce new bindings at the invocation site. Code such as the following will not work:

macro_rules! foo {
    () => (let x = 3);
}

fn main() {
    foo!();
    println!("{}", x);
}

rs39-8

Instead you need to pass the variable name into the invocation, so it’s tagged with the right syntax context.

macro_rules! foo {
    ($v:ident) => (let $v = 3);
}

fn main() {
    foo!(x);
    println!("{}", x);
}

rs39-9

This holds for let bindings and loop labels, but not for items. So the following code does compile:

macro_rules! foo {
    () => (fn x() { println!("hi!"); });
}

fn main() {
    foo!();
    x();
}

rs39-10

OK, quasi fatto pace con le macros 😉 poi continuo 😀
:mrgreen:

Rust – il linguaggio – 38

12144939

Continuo oggi inizio una cosa panicosa in altri linguaggi, non sempre fatta come si deve dovrebbe, le macros /usr/local/share/doc/rust/html/book/macros.html.
Uhmmmm… da distribuire in diversi posts per assimilarlo in piccole dosi 🙄

Macros

By now you’ve learned about many of the tools Rust provides for abstracting and reusing code. These units of code reuse have a rich semantic structure. For example, functions have a type signature, type parameters have trait bounds, and overloaded functions must belong to a particular trait.

This structure means that Rust’s core abstractions have powerful compile-time correctness checking. But this comes at the price of reduced flexibility. If you visually identify a pattern of repeated code, you may find it’s difficult or cumbersome to express that pattern as a generic function, a trait, or anything else within Rust’s semantics.

Macros allow us to abstract at a syntactic level. A macro invocation is shorthand for an “expanded” syntactic form. This expansion happens early in compilation, before any static checking. As a result, macros can capture many patterns of code reuse that Rust’s core abstractions cannot.

The drawback is that macro-based code can be harder to understand, because fewer of the built-in rules apply. Like an ordinary function, a well-behaved macro can be used without understanding its implementation. However, it can be difficult to design a well-behaved macro! Additionally, compiler errors in macro code are harder to interpret, because they describe problems in the expanded code, not the source-level form that developers use.

These drawbacks make macros something of a “feature of last resort”. That’s not to say that macros are bad; they are part of Rust because sometimes they’re needed for truly concise, well-abstracted code. Just keep this tradeoff in mind.

Definire una macro

You may have seen the vec! macro, used to initialize a vector with any number of elements.

fn main() {
    let x: Vec = vec![1, 2, 3];
    println!("[{} {} {}]", x[0], x[1], x[2]);
}

rs38-0

This can’t be an ordinary function, because it takes any number of arguments. But we can imagine it as syntactic shorthand for

fn main() {
    let x: Vec = {
        let mut temp_vec = Vec::new();
        temp_vec.push(1);
        temp_vec.push(2);
        temp_vec.push(3);
        temp_vec
    };
    println!("[{} {} {}]", x[0], x[1], x[2]);
}

rs38-1

We can implement this shorthand, using a macro
Note: The actual definition of vec! in libcollections differs from the one presented here, for reasons of efficiency and reusability.

macro_rules! vec {
    ( $( $x:expr ),* ) => {
        {
            let mut temp_vec = Vec::new();
            $(
                temp_vec.push($x);
            )*
            temp_vec
        }
    };
}

fn main() {
    let eq = vec![1,2,3] == [1, 2, 3];
    println!("{}", eq);
}

rs38-2

Whoa, that’s a lot of new syntax! Let’s break it down.

macro_rules! vec { ... }

This says we’re defining a macro named vec, much as fn vec would define a function named vec. In prose, we informally write a macro’s name with an exclamation point, e.g. vec!. The exclamation point is part of the invocation syntax and serves to distinguish a macro from an ordinary function.

Matching

The macro is defined through a series of rules, which are pattern-matching cases. Above, we had

( $( $x:expr ),* ) => { ... };

This is like a match expression arm, but the matching happens on Rust syntax trees, at compile time. The semicolon is optional on the last (here, only) case. The “pattern” on the left-hand side of => is known as a ‘matcher’. These have their own little grammar [/usr/local/share/doc/rust/html/reference.html#macros] within the language.

The matcher $x:expr will match any Rust expression, binding that syntax tree to the ‘metavariable’ $x. The identifier expr is a ‘fragment specifier’; the full possibilities are enumerated later in this chapter prossimi posts. Surrounding the matcher with $(...),* will match zero or more expressions, separated by commas.

Aside from the special matcher syntax, any Rust tokens that appear in a matcher must match exactly. For example,

macro_rules! foo {
    (x => $e:expr) => (println!("mode X: {}", $e));
    (y => $e:expr) => (println!("mode Y: {}", $e));
}

fn main() {
    foo!(y => 3);
}

rs38-3

OK, with foo!(z => 3); we get the compiler error:

macro_rules! foo {
    (x => $e:expr) => (println!("mode X: {}", $e));
    (y => $e:expr) => (println!("mode Y: {}", $e));
}

fn main() {
    foo!(z => 3);
}

rs38-4

Pausa 😀

:mrgreen:

Rust – il linguaggio – 37

3C273 Chandra

3C273 Chandra

Continuo, oggi qui: /usr/local/share/doc/rust/html/book/deref-coercions.html.

Deref coercions

The standard library provides a special trait, Deref. It’s normally used to overload *, the dereference operator:

use std::ops::Deref;

struct DerefExample {
    value: T,
}

impl Deref for DerefExample {
    type Target = T;

    fn deref(&self) -> &T {
        &self.value
    }
}

fn main() {
    let x = DerefExample { value: 'a' };
    assert_eq!('a', *x);
    println!("{} {}", 'a', *x);
}

rs37-0This is useful for writing custom pointer types. However, there’s a language feature related to Deref: ‘deref coercions’. Here’s the rule: If you have a type U, and it implements Deref<Target=T>, values of &U will automatically coerce to a &T. Here’s an example:

fn foo(s: &str) {
    // borrow a string for a second
}

// String implements Deref
let owned = "Hello".to_string();

// therefore, this works:
foo(&owned);

Using an ampersand in front of a value takes a reference to it. So owned is a String, &owned is an &String, and since impl Deref<Target=str> for String, &String will deref to &str, which foo() takes.

That’s it. This rule is one of the only places in which Rust does an automatic conversion for you, but it adds a lot of flexibility. For example, the Rc<T> type implements Deref<Target=T>, so this works:

fn main() {
    use std::rc::Rc;
    
    fn foo(s: &str) {
        // borrow a string for a second
    }
    
    // String implements Deref
    let owned = "Hello".to_string();
    let counted = Rc::new(owned);
    
    // therefore, this works:
    foo(&counted);
    println!("{}", counted);
}

rs37-1All we’ve done is wrap our String in an Rc<T>. But we can now pass the Rc<String> around anywhere we’d have a String. The signature of foo didn’t change, but works just as well with either type. This example has two conversions: Rc<String> to String and then String to &str. Rust will do this as many times as possible until the types match.

Another very common implementation provided by the standard library is:

fn main() {
    fn foo(s: &[i32]) {
        // borrow a slice for a second
    }
    
    // Vec implements Deref
    let owned = vec![1, 2, 3];
    
    foo(&owned);
    println!("{}", owned[0]);
}

rs37-2Vectors can Deref to a slice.

Deref e chiamate a metodo

Deref will also kick in when calling a method. Consider the following example:

fn main() {
    struct Foo;
    
    impl Foo {
        fn foo(&self) { println!("Foo"); }
    }
    
    let f = &&Foo;
    
    f.foo();
}

rs37-3

Even though f is a &&Foo and foo takes &self, this works. That’s because these things are the same:

f.foo();
(&f).foo();
(&&f).foo();
(&&&&&&&&f).foo();

A value of type &&&&&&&&&&&&&&&&Foo can still have methods defined on Foo called, because the compiler will insert as many * operations as necessary to get it right. And since it’s inserting *s, that uses Deref. 🙄

:mrgreen:

Rust – il linguaggio – 36

dsc_2388

Oggi qui: /usr/local/share/doc/rust/html/book/operators-and-overloading.html continuando da qui.

Operatori e overloading

Rust allows for a limited form of operator overloading. There are certain operators that are able to be overloaded. To support a particular operator between types, there’s a specific trait that you can implement, which then overloads the operator.

For example, the + operator can be overloaded with the Add trait:

use std::ops::Add;

#[derive(Debug)]
struct Point {
    x: i32,
    y: i32,
}

impl Add for Point {
    type Output = Point;

    fn add(self, other: Point) -> Point {
        Point { x: self.x + other.x, y: self.y + other.y }
    }
}

fn main() {
    let p1 = Point { x: 1, y: 0 };
    let p2 = Point { x: 2, y: 3 };

    let p3 = p1 + p2;

    println!("{:?}", p3);
}

rs36-0In main, we can use + on our two Points, since we’ve implemented Add<Output=Point> for Point.

There are a number of operators that can be overloaded this way, and all of their associated traits live in the std::ops [/usr/local/share/doc/rust/html/std/ops/index.html] module. Check out its documentation for the full list.

Implementing these traits follows a pattern. Let’s look at Add in more detail:

pub trait Add {
    type Output;

    fn add(self, rhs: RHS) -> Self::Output;
}

There’s three types in total involved here: the type you impl Add for, RHS, which defaults to Self, and Output. For an expression let z = x + y, x is the Self type, y is the RHS, and z is the Self::Output type.

mpl Add for Point {
    type Output = f64;

    fn add(self, rhs: i32) -> f64 {
        // add an i32 to a Point and get an f64
    }
}

will let you do this:

let p: Point = // ...
let x: f64 = p + 2i32;

Un po’ misterioso, l’esempio non sono riuscito a farlo funzionare, chissà se sono ancora troppo niubbo 🙄

Usare traits di operatori in structs generiche

Now that we know how operator traits are defined, we can define our HasArea trait and Square struct from the traits chapter more generically:

use std::ops::Mul;

trait HasArea {
    fn area(&self) -> T;
}

struct Square {
    x: T,
    y: T,
    side: T,
}

impl HasArea for Square
        where T: Mul<Output=T> + Copy {
    fn area(&self) -> T {
        self.side * self.side
    }
}

fn main() {
    let s = Square {
        x: 0.0f64,
        y: 0.0f64,
        side: 12.0f64,
    };

    println!("Area of s: {}", s.area());
}

rs36-1OK, un paio i warnings ma tutto OK.
For HasArea and Square, we just declare a type parameter T and replace f64 with it. The impl needs more involved modifications:

impl HasArea for Square
        where T: Mul<Output=T> + Copy { ... }

The area method requires that we can multiply the sides, so we declare that type T must implement std::ops::Mul. Like Add, mentioned above, Mul itself takes an Output parameter: since we know that numbers don’t change type when multiplied, we also set it to T. T must also support copying, so Rust doesn’t try to move self.side into the return value.

Non esattamente la cosa più semplice, imho 🙄

:mrgreen: