Rust – il linguaggio – 11

CaKOggi qui: /usr/local/share/doc/rust/html/book/mutability.html proseguendo da qui.

Mutabilità

Mutability, the ability to change something, works a bit differently in Rust than in other languages. The first aspect of mutability is its non-default status:

let x = 5;
x = 6; // error!

We can introduce mutability with the mut keyword:

let mut x = 5;
x = 6; // no problem!

This is a mutable variable binding. When a binding is mutable, it means you’re allowed to change what the binding points to. So in the above example, it’s not so much that the value at x is changing, but that the binding changed from one i32 to another.

If you want to change what the binding points to, you’ll need a mutable reference:

let mut x = 5;
let y = &mut x;

y is an immutable binding to a mutable reference, which means that you can’t bind y to something else (y = &mut z), but you can mutate the thing that’s bound to y (*y = 5). A subtle distinction.

Of course, if you need both:

let mut x = 5;
let mut y = &mut x;

Now y can be bound to another value, and the value it’s referencing can be changed.

It’s important to note that mut is part of a pattern, so you can do things like this:

let (mut x, y) = (5, 6);
fn foo(mut x: i32) {

Mutabilità interna e esterna

Così ho tradotto “Interior vs. Exterior Mutability”.
However, when we say something is ‘immutable’ in Rust, that doesn’t mean that it’s not able to be changed: we mean something has ‘exterior mutability’. Consider, for example, Arc<T>:

use std::sync::Arc;
let x = Arc::new(5);
let y = x.clone();

When we call clone(), the Arc<T> needs to update the reference count. Yet we’ve not used any muts here, x is an immutable binding, and we didn’t take &mut 5 or anything. So what gives?

To understand this, we have to go back to the core of Rust’s guiding philosophy, memory safety, and the mechanism by which Rust guarantees it, the ownership system, and more specifically, borrowing:

You may have one or the other of these two kinds of borrows, but not both at the same time:

  • one or more references (&T) to a resource,
  • exactly one mutable reference (&mut T).

So, that’s the real definition of ‘immutability’: is this safe to have two pointers to? In Arc<T>’s case, yes: the mutation is entirely contained inside the structure itself. It’s not user facing. For this reason, it hands out &T with clone(). If it handed out &mut Ts, though, that would be a problem.

Other types, like the ones in the std::cell module, have the opposite: interior mutability. For example:

use std::cell::RefCell;
let x = RefCell::new(42);
let y = x.borrow_mut();

RefCell hands out &mut references to what’s inside of it with the borrow_mut() method. Isn’t that dangerous? What if we do:

use std::cell::RefCell;
let x = RefCell::new(42);
let y = x.borrow_mut();
let z = x.borrow_mut();

This will in fact panic, at runtime. This is what RefCell does: it enforces Rust’s borrowing rules at runtime, and panic!s if they’re violated. This allows us to get around another aspect of Rust’s mutability rules. Let’s talk about it first.

Mutabilità field-level

Mutability is a property of either a borrow (&mut) or a binding (let mut). This means that, for example, you cannot have a struct with some fields mutable and some immutable:

struct Point {     
    x: i32,
    mut y: i32, // nope
}

The mutability of a struct is in its binding:

struct Point {
    x: i32,
    y: i32,
}

However, by using Cell<T>, you can emulate field-level mutability:

fn main() {
    use std::cell::Cell;
    
    struct Point {
        x: i32,
        y: Cell,
    }
    
    let point = Point { x: 5, y: Cell::new(6) };
    
    point.y.set(7);
    
    println!("y: {:?}", point.y);
    
}

rs11-0We’ve successfully updated y.

Uhmmm… ed è ancora lunga… :roll:
:mrgreen:

Computer SpaceGames

csg
Forse non vale; forse sto facendo una cosa non corretta ma devo farla.
Anche perché io ho cominciato troppo presto ma conosco chi ha vissuto in pieno questa era: quella del Basic, quella dei primi PC, l’inizio dell’era moderna, che ha messo KO i dinosauri, manframes e mini (i mini –ehi! il mio Pr1me— non erano per niente mini, erano armadi quattro stagioni).
Allora quando ho visto il tweet di John Regehr: I had this book ho visto che dovevo dirlo a tutti quelli che non seguono John su Twitter.

Über-fantastico vero?
Del Pr1me ne parlavo, tanto tempo fa, qui.

Rust – il linguaggio – 10

m4

Continuando da qui oggi ecco /usr/local/share/doc/rust/html/book/lifetimes.html.

Lifetimes

Sì contina con i due post precedenti sull’ownership. These three chapters are related, and in order. You’ll need all three to fully understand the ownership system.

Salto il paragrafo “Meta”, sempre uguale.

Lending out a reference to a resource that someone else owns can be complicated. For example, imagine this set of operations:

  • I acquire a handle to some kind of resource.
  • I lend you a reference to the resource.
  • I decide I’m done with the resource, and deallocate it, while you still have your reference.
  • You decide to use the resource.

Uh oh! Your reference is pointing to an invalid resource. This is called a dangling pointer or ‘use after free’, when the resource is memory.

To fix this, we have to make sure that step four never happens after step three. The ownership system in Rust does this through a concept called lifetimes, which describe the scope that a reference is valid for.

When we have a function that takes a reference by argument, we can be implicit or explicit about the lifetime of the reference:

// implicit
fn foo(x: &i32) {
}

// explicit
fn bar<'a>(x: &'a i32) {
}

The 'a reads ‘the lifetime a’. Technically, every reference has some lifetime associated with it, but the compiler lets you elide (i.e. omit, see “Lifetime Elision” below) them in common cases. Before we get to that, though, let’s break the explicit example down:

fn bar<'a>(...)

We previously talked a little about function syntax [/usr/local/share/doc/rust/html/book/functions.html], but we didn’t discuss the <>s after a function’s name. A function can have ‘generic parameters’ between the <>s, of which lifetimes are one kind. We’ll discuss other kinds of generics later in the book [/usr/local/share/doc/rust/html/book/generics.html], but for now, let’s just focus on the lifetimes aspect.

We use <> to declare our lifetimes. This says that bar has one lifetime, 'a. If we had two reference parameters, it would look like this:

fn bar<'a, 'b>(...)

Then in our parameter list, we use the lifetimes we’ve named:

...(x: &'a i32)

If we wanted an &mut reference, we’d do this:

...(x: &'a mut i32)

If you compare &mut i32 to &'a mut i32, they’re the same, it’s just that the lifetime 'a has snuck in between the & and the mut i32. We read &mut i32 as ‘a mutable reference to an i32’ and &'a mut i32 as ‘a mutable reference to an i32 with the lifetime 'a’.

Nelle struct

You’ll also need explicit lifetimes when working with structs:

struct Foo {
    x: &'a i32,
}

fn main() {
    let y = &5; // this is the same as `let _y = 5; let y = &_y;`
    let f = Foo { x: y };

    println!("{}", f.x);
}

rs10-0As you can see, structs can also have lifetimes. In a similar way to functions,

struct Foo<'a> {

declares a lifetime, and

x: &'a i32

uses it. So why do we need a lifetime here? We need to ensure that any reference to a Foo cannot outlive the reference to an i32 it contains.

Blocchi impl

Let’s implement a method on Foo:

struct Foo {
    x: &'a i32,
}

impl Foo {
    fn x(&self) -> &'a i32 { self.x }
}

fn main() {
    let y = &5; // this is the same as `let _y = 5; let y = &_y;`
    let f = Foo { x: y };

    println!("x is: {}", f.x());
}

rs10-1As you can see, we need to declare a lifetime for Foo in the impl line. We repeat 'a twice, just like on functions: impl<'a> defines a lifetime 'a, and Foo<'a> uses it.
Ahemmm:roll:

Lifetimes multiple

If you have multiple references, you can use the same lifetime multiple times:

fn x_or_y<'a>(x: &'a str, y: &'a str) -> &'a str {

This says that x and y both are alive for the same scope, and that the return value is also alive for that scope. If you wanted x and y to have different lifetimes, you can use multiple lifetime parameters:

fn x_or_y<'a, 'b>(x: &'a str, y: &'b str) -> &'a str {

In this example, x and y have different valid scopes, but the return value has the same lifetime as x.

Pensare per scopes

A way to think about lifetimes is to visualize the scope that a reference is valid for. For example:

fn main() {
    let y = &5;     // -+ y goes into scope
                    //  |
    // stuff        //  |
                    //  |
}                   // -+ y goes out of scope

Adding in our Foo:

struct Foo {
    x: &'a i32,
}

fn main() {
    let y = &5;           // -+ y goes into scope
    let f = Foo { x: y }; // -+ f goes into scope
    // stuff              //  |
                          //  |
}                         // -+ f and y go out of scope

Our f lives within the scope of y, so everything works. What if it didn’t? This code won’t work:

struct Foo {
    x: &'a i32,
}

fn main() {
    let x;                    // -+ x goes into scope
                              //  |
    {                         //  |
        let y = &5;           // ---+ y goes into scope
        let f = Foo { x: y }; // ---+ f goes into scope
        x = &f.x;             //  | | error here
    }                         // ---+ f and y go out of scope
                              //  |
    println!("{}", x);        //  |
}

rs10-2atz! :shock: Whew! As you can see here, the scopes of f and y are smaller than the scope of x. But when we do x = &f.x, we make x a reference to something that’s about to go out of scope.

Named lifetimes are a way of giving these scopes a name. Giving something a name is the first step towards being able to talk about it.

'static

The lifetime named ‘static’ is a special lifetime. It signals that something has the lifetime of the entire program. Most Rust programmers first come across 'static when dealing with strings:

let x: &'static str = "Hello, world.";

String literals have the type &'static str because the reference is always alive: they are baked into the data segment of the final binary. Another example are globals:

static FOO: i32 = 5;
let x: &'static i32 = &FOO;

This adds an i32 to the data segment of the binary, and x is a reference to it.

Lifetime elision

Rust supports powerful local type inference in function bodies, but it’s forbidden in item signatures to allow reasoning about the types based on the item signature alone. However, for ergonomic reasons a very restricted secondary inference algorithm called “lifetime elision” applies in function signatures. It infers only based on the signature components themselves and not based on the body of the function, only infers lifetime parameters, and does this with only three easily memorizable and unambiguous rules. This makes lifetime elision a shorthand for writing an item signature, while not hiding away the actual types involved as full local inference would if applied to it. (Cioè :shock: mica sicuro di aver capito :roll:, spero che la spiegazione renda questa frase barocca e principalmente decorativa).

When talking about lifetime elision, we use the term input lifetime and output lifetime. An input lifetime is a lifetime associated with a parameter of a function, and an output lifetime is a lifetime associated with the return value of a function. For example, this function has an input lifetime:

fn foo<'a>(bar: &'a str)

This one has an output lifetime:

fn foo<'a>() -> &'a str

This one has a lifetime in both positions:

fn foo<'a>(bar: &'a str) -> &'a str

Here are the three rules:

  • Each elided lifetime in a function’s arguments becomes a distinct lifetime parameter.
  • If there is exactly one input lifetime, elided or not, that lifetime is assigned to all elided lifetimes in the return values of that function.
  • If there are multiple input lifetimes, but one of them is &self or &mut self, the lifetime of self is assigned to all elided output lifetimes.

Otherwise, it is an error to elide an output lifetime.

Esempi

Here are some examples of functions with elided lifetimes. We’ve paired each example of an elided lifetime with its expanded form.

fn print(s: &str); // elided
fn print(s: &'a str); // expanded

fn debug(lvl: u32, s: &str); // elided
fn debug(lvl: u32, s: &'a str); // expanded

// In the preceding example, `lvl` doesn’t need a lifetime because it’s not a
// reference (`&`). Only things relating to references (such as a `struct`
// which contains a reference) need lifetimes.

fn substr(s: &str, until: u32) -> &str; // elided
fn substr(s: &'a str, until: u32) -> &'a str; // expanded

fn get_str() -> &str; // ILLEGAL, no inputs

fn frob(s: &str, t: &str) -> &str; // ILLEGAL, two inputs
fn frob(s: &'a str, t: &'b str) -> &str; // Expanded: Output lifetime is ambiguous

fn get_mut(&mut self) -> &mut T; // elided
fn get_mut(&'a mut self) -> &'a mut T; // expanded

fn args(&mut self, args: &[T]) -> &mut Command; // elided
fn args(&'a mut self, args: &'b [T]) -> &'a mut Command; // expanded

fn new(buf: &mut [u8]) -> BufWriter; // elided
fn new(buf: &'a mut [u8]) -> BufWriter; // expanded

:evil: quasi panico, forse.

:mrgreen:

Visto nel Web – 221

Allora oggi ci sono le categorie, ancora provvisorie, devo migliorarele, servono suggerimenti. CMQ ecco cosa ho visto nel Web.

domenico-scilipoti
Internet speed in Europe
#:Web, Internet
::: ianbremmer

Data about os used at the FOSDEM
#:free open source software
::: Google+

General birthday problem
#:algoritmi, codice
::: John D. Cook

European SpaceDataHighway’s first satellite lifts off
#:hardware #:sicurezza, spionaggio
::: Engadget

Apple: Losing Out On Talent and In Need of a Killer New Device
#:ditte
::: Slashdot

nq160122

Un attacco informatico e 50 milioni di euro in fumo … quale lezione?
#:sicurezza, spionaggio
::: Tech Economy

What is open hardware?
#:hardware #:free open source software
::: Opensource

Here’s some of the Apollo 11 source code
#:storia
::: randal_olson

Rust for Web
#:linguaggi di programmazione
::: Medium

Microsoft Edge’s Private Browsing Mode Isn’t Actually Private
#:sicurezza, spionaggio
::: Slashdot

CZUQtAcW0AAUjaM

Feature Comparison: LibreOffice – Microsoft Office
#:free open source software
::: The Document Foundation

Big Satellite Systems, Simulated On Your Desktop
#:Web, Internet #:innovazioni, futuro
::: Slashdot

La Marca monomarca
#:free open source software
::: Tech Economy

#madswag
#:economia #:spam
::: kOoLiNuS

RTFM
#:sistemi operativi
::: cosmo e dintorni

2012-05-31-einstein

Back to the stone age!
#:dispositivi mobili #:umorismo
::: SciencePorn

#lisp Picrin – a lightweight R7RS scheme implementation in pure C89
#:lisp e derivati
::: reddit_lisp

#lisp SBCL 1.3.2 released! | redd.it/43kuq7
io sono fermo a 1.2.14, come passa il tempo; sono vecchio :roll:
#:lisp e derivati
::: reddit_lisp

emacs is like a hobby
#:umorismo
::: ErgoEmacs

Mary livecodes a drum machine
#:algoritmi, codice
::: Mary Rose Cook

road

Default random-number generators are slow
#:algoritmi, codice
::: Daniel Lemire

How To Build a TimesMachine
#:algoritmi, codice #:storia #:dati, raccolta
::: Slashdot

Alphabet Becomes The Most Valuable Public Company In The World
#:ditte
::: TechCrunch

Harvard: No, Crypto Isn’t Making the FBI Go Dark
#:sicurezza, spionaggio
::: Slashdot

The Guix System Distribution
#:sistemi operativi #:free open source software
::: GNU

dark-side

On WebKit Security Updates
#:sicurezza, spionaggio
::: GNOME Blogs

“Così abbiamo convinto il Ministero della Difesa a convertirsi all’open-source”
#:free open source software
::: Motherboard

Expand Your #Programming Vocabulary (for Beginners)
#:linguaggi di programmazione
::: Donearm

Backslashes
#:umorismo
::: xkcd

12647446_1294591863904147_7754700145032717863_n

Safe Harbor addio, arriva il nuovo accordo Privacy Shield tra Europa e USA
#:sicurezza, spionaggio #:dati, raccolta
::: Downloadblog

8 non-code ways to contribute to open source
#:free open source software
::: Opensource

Microsoft steps up AI push with Swiftkey deal
#:ditte
::: Financial Times

Gavin McGimpsey wrote a nice macro outline as an introduction to Racket macros
#:lisp e derivati
::: racketlang

Tianhe-2 is the world’s fastest supercomputer powered by Linux
#:sistemi operativi
::: letozaf

12670617_10208843459187057_3563909602246832200_n

The TPP is a continuation of our disastrous trade policies that have devastated manufacturing cities and towns all over this country
#:economia
::: BernieSanders

Latest #Windows10 May Have a #Linux Subsystem Hidden Inside!
#:sistemi operativi
::: EPietrafesa

Be sure to read our #PrivacyShield fact sheet to better understand the agreement
#:sicurezza, spionaggio
::: CommerceGov

Linux 0.11 source code
#:storia #:sistemi operativi #:free open source software
::: gigitux

UN panel ‘rules in Julian Assange’s favour’
#:sicurezza, spionaggio
::: BBC ::: la Repubblica

CaKOa5rWYAAMWEC

Google’s new head of search is an AI research leader
#:ditte #:algoritmi, codice
::: Engadget

Today, 77% of adults ages 30-49 use social media, compared with 8% in 2005
#:social media
::: pewinternet

This looks big, if early reports are correct: UN finds UK unlawfully detained @WikiLeaks founder #Assange
#:sicurezza, spionaggio
::: Snowden

Torrents Time Lets Anyone Launch Their Own Web Version of Popcorn Time
#:Web, Internet
::: Slashdot

Fear of Macros
#:lisp e derivati
devo ancora leggerlo, poi vi racconto :wink:
::: Greg Hendershott

CaP4aLIWAAIeuxg

Latest Windows 10 May Have a Linux Subsystem Hidden Inside
#:sistemi operativi
::: The Hacker News

With Rand Paul out of the race, is there anyone left to fight the NSA?
#:sicurezza, spionaggio
::: The Verge

L’ultrabroadband in Italia
#:Web, Internet
::: manteblog

GNU Guile 2.1.2 released!
::: davexunit

Mozilla to end development on Firefox OS for smartphones after v2.6
::: daw985

vRF9b47

ABC della sicurezza: Furto di Identità
#:sicurezza, spionaggio
::: Tech Economy

“Sfiduciati” sulla strada del CAD: coinvolgiamo tutti gli stakeholder
::: Forum PA

Apple, pizza e mandolino
#:ditte
::: Un altro orizzonte

New Concurrent Hash Maps for C++
#:algoritmi, codice
::: Preshing on Programming

A Brief History of Open Source Code – Infographic by Kinvey
#:free open source software #:storia
::: BSD MAG

CaZTSXjWEAALCet

Privacy, il nuovo accordo tra Europa e Usa ci tutela davvero?
#:sicurezza, spionaggio
::: L’Espresso

AI Is Transforming Google Search. The Rest of the Web Is Next
#:ditte #:innovazioni, futuro #:Web, Internet
::: Wired

Riconoscere un font
::: patfumetto

Heisenberg developers
#:programming, codice, snippet
::: Grab the Blaster

Marco Rubio Wants To Permanently Extend NSA Mass Surveillance
#:sicurezza, spionaggio
::: Slashdot

12654482_10208805769971395_5498060997450067380_n

Firefox 44 Deletes Fine-Grained Cookie Management
#:Web, Internet #:sicurezza, spionaggio
::: Slashdot

Renzi, Carrai e Padoan. Cosa succede davvero sulla cyber security
#:sicurezza, spionaggio
::: Formiche

Wearable Devices Market Worth $28.7 Billion In 2016: Smartwatch To Drive the Growth
#:dispositivi mobili
::: Dazeinfo

The Essence of Scala
#:programmazione funzionale
::: Scala

X projects: Alphabet’s ‘moonshot’ ventures that could change the world
#:ditte #:innovazioni, futuro
::: the Guardian

12669607_946359752079504_4494371113854956777_n

Error 53: Apple remotely bricks phones to punish customers for getting independent repairs
#:ditte
::: Boing Boing

Writing an Infrared Logic Analyser in Racket
#:lisp e derivati
::: (expr:labs)

Racket ships with a fantastic tileset for 2D games
#:lisp e derivati
::: thelittlelisper

Callback Hell: A guide to asynchronous #JavaScript programming
#:linguaggi di programmazione
::: Donearm

Brotli has potential to replace GZIP for compression of dynamic assets
#:algoritmi, codice
::: openwebdaily

12647115_537654666395690_8314991193723485884_n

The Performance of Ubuntu Linux Over the Past 10 Years
#:sistemi operativi
::: Slashdot

Don’t Sleep On New Data Privacy Regulations
#:sicurezza, spionaggio
::: TechCrunch

Six degrees of separation?
#:sicurezza, spionaggio #:Web, Internet
::: Snowden

The Linux user experience
#:umorismo
::: thegrugq

Modern Java – A Guide to Java 8
#:manuali, how to #:linguaggi di programmazione
::: winterbe
CaiaevoW0AAvpr3

Rust – il linguaggio – 9

t3

Oggi qui: /usr/local/share/doc/rust/html/book/references-and-borrowing.html, continuando da qui.

References and Borrowing

Non traduco tanto quello si usa :roll:
This guide is two of three presenting Rust’s ownership system. Come detto nel post appena citato.

Meta

Importante quello che dice ma è la ripetizione di quello già detto. OK, salto, tanto i post vanno letti in sequenza, si sa.
With that in mind, let’s learn about borrowing.

Borrowing

At the end of the ownership [sì, sempre quel post] section, we had a nasty function that looked like this:

fn foo(v1: Vec, v2: Vec) -> (Vec, Vec, i32) {
    // do stuff with v1 and v2

    // hand back ownership, and the result of our function
    (v1, v2, 42)
}
let v1 = vec![1, 2, 3];
let v2 = vec![1, 2, 3];
let (v1, v2, answer) = foo(v1, v2);

This is not idiomatic Rust, however, as it doesn’t take advantage of borrowing. Here’s the first step (l’ho modificato per togliere i warnings):

fn main() {
    fn foo(v1: &Vec, v2: &Vec) -> i32 {
        // do stuff with v1 and v2
        let x = v1[1] + v2[2];
        println!("x vale {}", x);
        // return the answer
        42
    }
    
    let v1 = vec![1, 2, 3];
    let v2 = vec![1, 2, 3]; 
    let answer = foo(&v1, &v2); // we can use v1 and v2 here!
    println!("La risposta è {}", answer);
}

rs9-0Instead of taking Vec<i32>s as our arguments, we take a reference: &Vec<i32>. And instead of passing v1 and v2 directly, we pass &v1 and &v2. We call the &T type a ‘reference’, and rather than owning the resource, it borrows ownership. A binding that borrows something does not deallocate the resource when it goes out of scope. This means that after the call to foo(), we can use our original bindings again.

References are immutable, just like bindings. This means that inside of foo(), the vectors can’t be changed at all:

fn foo(v: &Vec) {
     v.push(5);
}
let v = vec![];
foo(&v);

errors with: error: cannot borrow immutable borrowed content `*v` as mutable v.push(5);

Pushing a value mutates the vector, and so we aren’t allowed to do it.

&mut references

There’s a second kind of reference: &mut T. A ‘mutable reference’ allows you to mutate the resource you’re borrowing. For example:

fn main() {
    let mut x = 5;
    {
        let y = &mut x;
        *y += 1;
    }
    println!("{}", x);
}

rs9-1We make y a mutable reference to x, then add one to the thing y points at. You’ll notice that x had to be marked mut as well, if it wasn’t, we couldn’t take a mutable borrow to an immutable value.

You’ll also notice we added an asterisk (*) in front of y, making it *y, this is because y is an &mut reference. You’ll also need to use them for accessing the contents of a reference as well.

Otherwise, &mut references are just like references. There is a large difference between the two, and how they interact, though. You can tell something is fishy in the above example, because we need that extra scope, with the { and }. If we remove them, we get an error:

error: cannot borrow `x` as immutable because it is also borrowed as mutable
    println!("{}", x);
                   ^

note: previous borrow of `x` occurs here; the mutable borrow prevents subsequent moves, borrows, or modification of `x` until the borrow ends let y = &mut x;.

note: previous borrow ends here
fn main() {

}
^

As it turns out, there are rules. :roll: Logico ma pistino assay! :roll:

Le regole

The rules dice lui.
First, any borrow must last for a scope no greater than that of the owner. Second, you may have one or the other of these two kinds of borrows, but not both at the same time:

  • one or more references (&T) to a resource,
  • exactly one mutable reference (&mut T).

You may notice that this is very similar, though not exactly the same as, to the definition of a data race:

There is a ‘data race’ when two or more pointers access the same memory location at the same time, where at least one of them is writing, and the operations are not synchronized.

With references, you may have as many as you’d like, since none of them are writing. If you are writing, you need two or more pointers to the same memory, and you can only have one &mut at a time. This is how Rust prevents data races at compile time: we’ll get errors if we break the rules.
Qui mi sa che rischio di dimenticarmelo :roll: anche se è tremendamente logico :grin:

With this in mind, let’s consider our example again.

Pensare per scopes

Here’s the code:

let mut x = 5;
let y = &mut x;

*y += 1;

println!("{}", x);

This code gives us this error: error: cannot borrow `x` as immutable because it is also borrowed as mutable println!("{}", x);

This is because we’ve violated the rules: we have a &mut T pointing to x, and so we aren’t allowed to create any &Ts. One or the other. The note hints at how to think about this problem: l’indicatore di dov’è l’errore (il segno ^) si trova sotto la } finale.

In other words, the mutable borrow is held through the rest of our example. What we want is for the mutable borrow to end before we try to call println! and make an immutable borrow. In Rust, borrowing is tied to the scope that the borrow is valid for. And our scopes look like this:

let mut x = 5;
let y = &mut x;    // -+ &mut borrow of x starts here
                   //  |
*y += 1;           //  |
                   //  |
println!("{}", x); // -+ - try to borrow x here
                   // -+ &mut borrow of x ends here

The scopes conflict: we can’t make an &x while y is in scope.

So when we add the curly braces:

let mut x = 5;
{
    let y = &mut x; // -+ &mut borrow starts here
    *y += 1;        //  |
}                   // -+ ... and ends here

println!("{}", x);  // <- try to borrow x here

There’s no problem. Our mutable borrow goes out of scope before we create an immutable one. But scope is the key to seeing how long a borrow lasts for.

Problemi che il borrowing previene

Why have these restrictive rules? Well, as we noted, these rules prevent data races. What kinds of issues do data races cause? Here’s a few.

invalidazione di iteratori
One example is ‘iterator invalidation’, which happens when you try to mutate a collection that you’re iterating over. Rust’s borrow checker prevents this from happening:

fn main() {
    let v = vec![1, 2, 3];
    for i in &v {
        println!("{}", i);
    }
}

rs9-2As we iterate through the vectors, we’re only given references to the elements. And v is itself borrowed as immutable, which means we can’t change it while we’re iterating:

fn main() {
    let mut v = vec![1, 2, 3];
    for i in &v {
        println!("{}", i);
        v.push(34);
    }
}

rs9-3We can’t modify v because it’s borrowed by the loop.

uso dopo il free (o devo dire deallocazione?)
References must not live longer than the resource they refer to. Rust will check the scopes of your references to ensure that this is true.
If Rust didn’t check this property, we could accidentally use a reference which was invalid. For example:

fn main() {
    let y: &i32;
    {
        let x = 5;
        y = &x;
    }
    println!("{}", y);

rs9-4y is only valid for the scope where x exists. As soon as x goes away, it becomes invalid to refer to it. As such, the error says that the borrow ‘doesn’t live long enough’ because it’s not valid for the right amount of time.
The same problem occurs when the reference is declared before the variable it refers to. This is because resources within the same scope are freed in the opposite order they were declared:

fn main() {
    let y: &i32;
    let x = 5;
    y = &x;
    println!("{}", y);

rs9-5In the above example, y is declared before x, meaning that y lives longer than x, which is not allowed.

Pensierino della sera (anche se non è l’ora): da sempre * e & sono –come dire… :roll:

:mrgreen:

Ancora Wallis

bb9Ancora qualche considerazioni sul post relativo al prodotto di Wallis.
Intanto la sua inefficienza, per ottenere un approssimazione decente occorrono davvero tante iterazioni, ecco, con Python:

#!/usr/bin/python3

# calcolo di pi con la formula di Wallis

p = 1            
lsup = 1000 * 1000 * 100 + 1
stp = lsup // 10
for n in range(1, lsup):
    t = 4 * pow(n, 2.0)
    p = p * t /(t - 1)
    if n % stp == 0:
    	print(n, p, 2 * p)

w-py

46 secondi per 100 milioni di iterazioni :grin:

Ma molto più interessante che non servono; dopo i 40 milioni il risultato non migliora; Il numero di cifre previste per il float è stato raggiunto e fine. Vero è che anche con Python si potrebbe fare molto meglio, con NumPy/SciPy, per esempio.

Ma se invece provassimo con Racket, il mio linguaggio preferito (ce ne sono tanti altri pari merito –quasi)?
Racket non approssima, ha il tipo rational [/usr/racket/doc/guide/numbers.html] e quindi si può prevedere… Provo.

Adesso devo confessare una cosa personale: nei periodi in cui mi occupo di linguaggi di programmazione diversi le mie prestazioni diminuiscono fortemente. Ultimamente sono alle prese con Rust (molto interessante, grazie Robitex), Python (da sempre, sono tendenzialmente evangelista Python) e –almeno in questo momento– Racket. Ecco faccio confusione, non riesco a ragionare in termini funzionali. Il codice che segue è la traduzione dello script Python, non è bello, potrei fare di meglio, abuso di set!, cosa evitabile con let (e let*). Anzi a mia idea era quella, non è detto che in futuro… :wink:
Inoltre, per ragioni di tempo il numero delle iterazioni è ridotto, un solo milione. Ecco cosa ottengo

#lang racket                        ;; wallis
                                    ;; product 
(define (wallis)
  (define t 0)
  (define p 1)
  (for ([n (range 1 1000001)])      ;; 1M
    (set! t (* 4 n n))
    (set! p (/ (* p t) (- t 1)))
    (when (zero? (modulo n 100000)) ;; 100K
      (printf "~a ~a ~a \n"
              n (exact->inexact p)
              (exact->inexact (* 2 p))))))

(wallis)

Semplice vero? Uso la procedura exact->inexact per visualizzare i risultati altrimenti è il diluvio.

Alla partenza mi trovo in queste condizioni:

i

Sì, una delle CPU è subito riservata al task, poi si procede

i2

intanto attendo, attendo, attendo e infine:

fine2

Quasi 81 minuti! E non si è raggiunta l’approssimazione di Python. Bisognerebbe proseguire ancora. Ma la vita è troppo breve; e io sono in ritardo :roll:

Racket dev’essere preso per il suo verso. E roll over Beethoven Wallis (quasi-cit.) :grin:

:mrgreen:

Rust – il linguaggio – 8

dorai

Continuando da qui oggi sono qui: /usr/local/share/doc/rust/html/book/ownership.html.

Ownership

Come tradurre? Possesso, sì, forse sì. Ma meglio vedere cos’è secondo Rust.

This is one of Rust’s most unique and compelling features, with which Rust developers should become quite acquainted. Ownership is how Rust achieves its largest goal, memory safety. There are a few distinct concepts, each with its own chapter:

  • ownership, which you’re reading now;
  • borrowing [/usr/local/share/doc/rust/html/book/references-and-borrowing.html], and their associated feature ‘references’;
  • lifetimes [/usr/local/share/doc/rust/html/book/lifetimes.html], an advanced concept of borrowing.

These three chapters are related, and in order. You’ll need all three to fully understand the ownership system.

Meta

Before we get to the details, two important notes about the ownership system.
Rust has a focus on safety and speed. It accomplishes these goals through many ‘zero-cost abstractions’, which means that in Rust, abstractions cost as little as possible in order to make them work. The ownership system is a prime example of a zero-cost abstraction. All of the analysis we’ll talk about in this guide is done at compile time. You do not pay any run-time cost for any of these features.
However, this system does have a certain cost: learning curve. Sì, conosco, e già sentito. Per non spaventare e spaventarmi faccio un salto avanti.

There is good news, however: more experienced Rust developers report that once they work with the rules of the ownership system for a period of time, they fight the borrow checker less and less. Yeah! :grin:

With that in mind, let’s learn about ownership.

Ownership

Variable bindings have a property in Rust: they ‘have ownership’ of what they’re bound to. This means that when a binding goes out of scope, Rust will free the bound resources. For example:

fn foo() {
    let v = vec![1, 2, 3];
}

When v comes into scope, a new Vec<T> is created. In this case, the vector also allocates space on the heap, for the three elements. When v goes out of scope at the end of foo(), Rust will clean up everything related to the vector, even the heap-allocated memory. This happens deterministically, at the end of the scope.

Semantica spostata

“Move semantics” dice la guida.
There’s some more subtlety here, though: Rust ensures that there is exactly one binding to any given resource. For example, if we have a vector, we can assign it to another binding:

let v = vec![1, 2, 3];
let v2 = v;  // attenzione qui :sad:

But, if we try to use v afterwards, we get an error:

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

rs8-0

A similar thing happens if we define a function which takes ownership, and try to use something after we’ve passed it as an argument:

fn main() {
    fn take(v: Vec) {
        // what happens here isn’t important.
    }
    let v = vec![1, 2, 3];
    take(v);
    println!("v[0] is: {}", v[0]);
}

rs8-1

Same error: ‘use of moved value’. When we transfer ownership to something else, we say that we’ve ‘moved’ the thing we refer to. You don’t need some sort of special annotation here, it’s the default thing that Rust does.

I dettagli

The reason that we cannot use a binding after we’ve moved it is subtle, but important. When we write code like this:

let v = vec![1, 2, 3];
let v2 = v;  // attenzione qui :sad:

The first line allocates memory for the vector object, v, and for the data it contains. The vector object is stored on the stack and contains a pointer to the content ([1, 2, 3]) stored on the heap. When we move v to v2, it creates a copy of that pointer, for v2. Which means that there would be two pointers to the content of the vector on the heap. It would violate Rust’s safety guarantees by introducing a data race. Therefore, Rust forbids using v after we’ve done the move.

It’s also important to note that optimizations may remove the actual copy of the bytes on the stack, depending on circumstances. So it may not be as inefficient as it initially seems.

Copy types

We’ve established that when ownership is transferred to another binding, you cannot use the original binding. However, there’s a trait that changes this behavior, and it’s called Copy. We haven’t discussed traits yet, but for now, you can think of them as an annotation to a particular type that adds extra behavior. For example:

fn main() {
    let v = 1;
    let v2 = v;
    println!("v is: {}", v);
}

rs8-2
In this case, v is an i32, which implements the Copy trait. This means that, just like a move, when we assign v to v2, a copy of the data is made. But, unlike a move, we can still use v afterward. This is because an i32 has no pointers to data somewhere else, copying it is a full copy.

All primitive types implement the Copy trait and their ownership is therefore not moved like one would assume, following the ´ownership rules´. To give an example, the two following snippets of code only compile because the i32 and bool types implement the Copy trait.

fn main() {
    let a = 5;

    let _y = double(a);
    println!("{}", a);
}

fn double(x: i32) -> i32 {
    x * 2
}

rs8-3

fn main() {

    let a = true;

    let _y = change_truth(a);
    println!("{}", a);
}

fn change_truth(x: bool) -> bool {
    !x
}

rs8-4

If we would have used types that do not implement the Copy trait, we would have gotten a compile error because we tried to use a moved value. Come abbiamo visto sopra, con double.

We will discuss how to make your own types Copy in the traits [/usr/local/share/doc/rust/html/book/traits.html] section.

Ancora sull’ownership

Of course, if we had to hand ownership back with every function we wrote:

fn foo(v: Vec) -> Vec {
    // do stuff with v
    // hand back ownership
    v
}

This would get very tedious. It gets worse the more things we want to take ownership of:

fn foo(v1: Vec, v2: Vec) -> (Vec, Vec, i32) {
    // do stuff with v1 and v2
    // hand back ownership, and the result of our function
    (v1, v2, 42)
}

let v1 = vec![1, 2, 3];
let v2 = vec![1, 2, 3];

let (v1, v2, answer) = foo(v1, v2);

Ugh! The return type, return line, and calling the function gets way more complicated.
Luckily, Rust offers a feature, borrowing, which helps us solve this problem. It’s the topic of the next section!

Uh! l’intrigo diventa intrigante :grin:

:mrgreen:

Attenti al falso amico con Python

mama

Un mystero mysteryouso, assay. Anzi no ma a volte capita :roll:
Ecco una formula curiosa che si presta a fare un esercizio sui cicli.

wallis

È il prodotto di Wallis, qui la pagina della Wiki (la versione italiana c’è ma meno completa).
Ah! converge molto lentamente, vale solo per questo esercizio.
Sembra semplice :grin:
Il primo tentativo è disastroso:

#!/usr/bin/python3

# calcolo di pi con la formula di Wallis
#ERRATO!!!

p = 1
for n in range(1, 11):
	t = 4 * n^2
	e = t / (t - 1)
	p = p * e 
	print(n, e, p, 2 * p)
print(2.0 * p)

i
Correggo, ecco:

#!/usr/bin/python3

# calcolo di pi con la formula di Wallis

p = 1.0
for n in range(1, 11):
	t = 4 * pow(n, 2.0)
	e = t /(t - 1)
	p = p * e 
	print(n, e, p, 2 * p)
print(2.0 * p)

r
Dov’è l’errore?

pow

La risposta è che a volte ci lasciamo ingannare dai falsi amici, esaminiamo interattivamente:

int

Ecco! Capita non solo in linguistica!

Poi il falso amico multilingua (l’originale è olandese) che preferisco e quello dell’immagine lassù in cima :loll:
Attualmente in italiano funziona foneticamente.

OK, tornando a Python l’elevazione a potenza si fa con pow() o ** (ehi! come in Fortran :grin:):

int2

Invece ^ è un operatore bitwise: The ^ operator yields the bitwise XOR (exclusive OR) of its arguments, which must be integers.

Verifico, con l’aiuto di bin():
xorSemplice vero? restituisce i bits settati a 1 per entrambi i numeri.
Caso risolto :grin:

:mrgreen:

Rust – il linguaggio – 7

pogo5

Oggi qui: /usr/local/share/doc/rust/html/book/loops.html, continuando da qui.

Cicli

Rust currently provides three approaches to performing some kind of iterative activity. They are: loop, while and for.

loop

loop {
    println!("Loop forever!");
}

while

fn main() {
    let mut x = 5; // mut x: i32
    let mut done = false; // mut done: bool

    while !done {
        x += x - 3;

        println!("{}", x);

        if x % 5 == 0 {
            done = true;
        }
    }
}

rs7-0

while loops are the correct choice when you’re not sure how many times you need to loop.

If you need an infinite loop, you may be tempted to write this:

while true {

However, loop is far better suited to handle this case:

loop {

Rust’s control-flow analysis treats this construct differently than a while true, since we know that it will always loop. In general, the more information we can give to the compiler, the better it can do with safety and code generation, so you should always prefer loop when you plan to loop infinitely. Ottimizzazione e chiarezza del codice :grin:

for

The for loop is used to loop a particular number of times. Rust’s for loops work a bit differently than in other systems languages, however. Rust’s for loop doesn’t look like this “C-style” for loop. Non metto il codice C, se poi leggo di fretta capace che mi perdo :roll:

[I]t looks like this:

for x in 0..10 {
    println!("{}", x); // x: i32
}

In slightly more abstract terms,

for var in expression {
    code
}

The expression is an iterator (prossimamente, qui: /usr/local/share/doc/rust/html/book/iterators.html). The iterator gives back a series of elements. Each element is one iteration of the loop. That value is then bound to the name var, which is valid for the loop body. Once the body is over, the next value is fetched from the iterator, and we loop another time. When there are no more values, the for loop is over.

In our example, 0..10 is an expression that takes a start and an end position, and gives an iterator over those values. The upper bound is exclusive, though, so our loop will print 0 through 9, not 10.

Rust does not have the “C-style” for loop on purpose. Manually controlling each element of the loop is complicated and error prone, even for experienced C developers.

fn main() {
    for x in 0..10 {
        print!("{} ", x); // x: i32
    }
    println!("");
}

rs7-1

Enumerate

When you need to keep track of how many times you already looped, you can use the .enumerate() function.

Per gli intervalli (ranges):

fn main() {
    for (i,j) in (5..10).enumerate() {
        println!("i = {} and j = {}", i, j);
    }
}

rs7-2

Con gli iteratori:

fn main() {
    let lines = "hello\nworld".lines();

    for (linenumber, line) in lines.enumerate() {
        println!("{}: {}", linenumber, line);
    }
}

rs7-3

Uscita anticipata dall’iterazione

Let’s take a look at that while loop we had earlier:

let mut x = 5;
let mut done = false;

while !done {
    x += x - 3;

    println!("{}", x);

    if x % 5 == 0 {
        done = true;
    }
}

We had to keep a dedicated mut boolean variable binding, done, to know when we should exit out of the loop. Rust has two keywords to help us with modifying iteration: break and continue.

In this case, we can write the loop in a better way with break:

fn main() {
    let mut x = 5;

    loop {
        x += x - 3;

        println!("{}", x);

        if x % 5 == 0 { break; }
    }
}

rs7-4We now loop forever with loop and use break to break out early. Issuing an explicit return statement will also serve to terminate the loop early.

fn main() {
    let mut x = 5;

    loop {
        x += x - 3;

        println!("{}", x);

        if x % 5 == 0 { return; }
    }
}

continue is similar, but instead of ending the loop, goes to the next iteration. This will only print the odd numbers:

fn main() {
    for x in 0..10 {
        if x % 2 == 0 { continue; }

        print!("{} ", x);
    }
    println!("");
}

rs7-5

Labels con i loops

You may also encounter situations where you have nested loops and need to specify which one your break or continue statement is for. Like most other languages, by default a break or continue will apply to innermost loop. In a situation where you would like to a break or continue for one of the outer loops, you can use labels to specify which loop the break or continue statement applies to. This will only print when both x and y are odd:

fn main() {
    'outer: for x in 0..6 {
        'inner: for y in 0..6 {
            if x % 2 == 0 { continue 'outer; } // continues the loop over x
            if y % 2 == 0 { continue 'inner; } // continues the loop over y
            println!("x: {}, y: {}", x, y);
        }
    }
}

rs7-6

Notare che la label dev’essere quotata à la Lisp.

:mrgreen:

LOL – Let Over Lambda

Quando uno ridefinisce così un acronimo universalmente riconosciuto al volo dev’essere un nerd davvero über. Ma ‘spetta’n’attimino: è un lisper, quelli che usano il programmable programming language, quello delle macro, quelle vere, mica la robetta di C/C++.
OK, adesso mi spiego :roll:
logoSto parlando di Doug Hoyte, ecco come si presenta, qui.
Sì ha un blog da seguire, cioè no, non è aggiornato, abbandonato. Anche la foto di allora è di quando era un über-nerd giovane. Adesso scrive su Hoytech che Feedly si rifiuta di RSSare. Da seguire autonomamente.

Anche perché la novità è non nuovissima ma di quelle ***BREAKING NEWS***: Let Over Lambda—50 Years of Lisp.

Un libro di quelli intimidatori per la mole, 384 pagine 15×23 cm, pieno di Common Lisp.
Poco per volta, per chi ha pazienza e pochi €, Doug lo sta mettendolo online; anche se è uno di quelli che qualificano la propria biblioteca :wink: ma attenti che se lo vedo lo prendo, vedo se ci sono segnalibri, lo apro e controllo sottolineature e note, nèh.

Io l’ho subito messo tra le cose da fare, non subitissimo ma abbastanza urgenti (non urgentissime). Altamente consigliato ai lispers tutti. E un ringraziamento particolare al prof Lipari :grin: che me l’ha segnalato.

:mrgreen:

Iscriviti

Ricevi al tuo indirizzo email tutti i nuovi post del sito.

Segui assieme ad altri 89 follower