News for hackers. Stuff that matters.
Re:Announcing Rust 1.22 by kibwen on Thursday November 23, 2017 @02:14AM (#15763412)
It's desirable from the standpoint of consistency, given that the following equivalent code has always worked:

  let mut x = 2;
  let y = &8;
  x = x + y;
What mistakes could this be masking? I can't think of any.
Re:Announcing Rust 1.22 by mkl on Thursday November 23, 2017 @02:31AM (#15763478)
I didn't realise it already worked in other contexts.

Mistakes in terms of understanding the code and writing what you think you're writing. I've only just begun learning Rust, and one of the most difficult things has been figuring out what types my variables have when everything is implicit and based on type inference. Variables that act both as pointers and non-pointers seem pretty confusing. It's like temporarily and invisibly turning off parts of the type-checker.

ETA: To me it feels a bit like the icky type coercion magic some languages have that lets you write code that kind of works even though you don't understand what you're doing. I don't know Rust though, so this may be totally different.

Re:Announcing Rust 1.22 by kibwen on Thursday November 23, 2017 @03:03AM (#15763598)
If you happen to be coming from C, keep in mind that integers in Rust don't coerce into anything else like they do in C; e.g. adding an 8-bit integer to a 32-bit integer (without an explicit cast) is a type error, `if 0` does not work, arithmetic ops on references never do pointer arithmetic, etc.
Re:Announcing Rust 1.22 by Manishearth on Thursday November 23, 2017 @07:01AM (#15764488)
> ETA: To me it feels a bit like the icky type coercion magic some languages have that lets you write code that kind of works even though you don't understand what you're doing. I don't know Rust though, so this may be totally different.

It is quite different.

In Rust already it is possible to proxy "pointer to a thing" as "the thing itself" in a lot of different places, making it a lot more pleasant to work with. This is a continuation of that trend.

It's pretty easy to know if most things are a pointer or not, but more importantly if it's not immediately obvious it rarely matters (i.e. you're not the one creating or consuming it; you're just sharing borrows to it). At which point sharing pointer-to-value vs pointer-to-pointer isn't very different, and Rust implicitly deals with that.

Re:Announcing Rust 1.22 by Gankro on Thursday November 23, 2017 @11:40AM (#15766153)
Ultimately it boils down to the fact that there's basically no interesting difference between an immutable reference to a primitive and the primitive itself in Rust. It can't dangle. The immutability can't be casted away. They just have a different ABI if the references don't get completely optimized away. You could do pointer equality checks on them if you really want?

Swift has taken the observation further and is investigating ways to avoid ever having a immutable+shared-reference-to-primitive vs primitive distinction in the language, while still introducing this distinction for types where it is interesting. (e.g. reference counted classes or atomics)

Re:Announcing Rust 1.22 by Jare on Thursday November 23, 2017 @02:47AM (#15763543)
Don't worry, by the time the borrow checker is done with you, you will understand what you are doing like you've never before. This is a good thing.
Re:Announcing Rust 1.22 by fredmorcos on Thursday November 23, 2017 @03:25AM (#15763681)
Okay, so I came from C and this part really put me off. Why? Because I like saying what I mean, and meaning what I say. Nothing hidden, nothing implicit. And C, as opposed to C++, does not allow you to say something you don't mean.

Here is one C++ example, without looking for the signature of f(), there's no way to tell the answer. So essentially two pieces of identical code with identical input values and no external side effects can still give you different output. Ah C++, the garbage that you are.

  int x = 5;
  f(x);
  // WHAT IS THE VALUE OF X HERE?

  int x = 5;
  f(x);
  // WHAT IS THE VALUE OF X HERE?
So why is Rust any better in this regard? Because at the end of the day, Rust deals with actual concrete types and values, the only thing references are good for is being references: they sometimes save you some copying and let you refer to stuff and that's pretty much it. So the "ref1 == ref2" operation is a deep equality check and not a "does ref1 point to the same object as ref2" check. Because sometimes objects in different places in memory can be semantically equal. So it's okay for obj1 to mean obj1, &obj1 to mean obj1, &&obj1 to mean obj1, etc...

If you need raw pointers like you need in C, because you know the objects you want to compare are singletons, then you can always cast using

  &obj as *const Obj
or

  &mut obj as *mut Obj
But that's an escape hatch.

BTW, this auto-dereferencing you're experiencing is part of the Deref trait if you ever want to overload it. But that's, in my own opinion, an escape hatch as well.

All in all, unless you're doing very specific things, try to write your code in high-level semantics (meaning using these deep-equality rather than pointer-equality semantics), and then benchmark and find out which parts are hurting your performance. Rust allows you to do that and still get between very-reasonable-and-very-good speed.

Re:Announcing Rust 1.22 by simias on Thursday November 23, 2017 @05:51AM (#15764256)
>Okay, so I came from C and this part really put me off. Why? Because I like saying what I mean, and meaning what I say. Nothing hidden, nothing implicit.

Are we talking about the same language here? The language where arrays implicitly decay to pointers, where integer types get implicitly promoted all over the place, where aliasing rules implicitly define which pointers can and cannot alias, where partial initialization of a struct or array implicitly sets the other members to 0? Where the language will let you call an undeclared function and make up a prototype on the fly for you?

I also don't understand your C++ example, without side-effect why would both invocations of f() within the same scope produce a different result? I thought you wanted to criticise function overloading but you call it with an int both times so I don't see what's you're getting at.

Or maybe you meant that the two calls are in a different scope and could resolve to a different function? But you can do that in C as well in two different translation units and making two static f() implementations.

Re:Announcing Rust 1.22 by fredmorcos on Thursday November 23, 2017 @08:34AM (#15764923)
> Are we talking about the same language here? The language where arrays implicitly decay to pointers, where integer types get implicitly promoted all over the place, where aliasing rules implicitly define which pointers can and cannot alias, where partial initialization of a struct or array implicitly sets the other members to 0? Where the language will let you call an undeclared function and make up a prototype on the fly for you?

-Wall -Wextra and those issues are made clear to you. But granted, that's part of a good compiler and not part of the language.

> I also don't understand your C++ example, without side-effect why would both invocations of f() within the same scope produce a different result? I thought you wanted to criticise function overloading but you call it with an int both times so I don't see what's you're getting at.

I'm not criticizing function overloading.

> Or maybe you meant that the two calls are in a different scope and could resolve to a different function? But you can do that in C as well in two different translation units and making two static f() implementations.

Yes the two functions are different, but not necessarily in scope, they don't necessarily need to have the same names. Yet at the calling site they look exactly the same: one will modify your data without you being aware of it and the other will not, and there is no syntactic hint to differentiate them.

Re:Announcing Rust 1.22 by gpderetta on Thursday November 23, 2017 @04:50AM (#15764014)

  int x = 5;
  f(x);
  // WHAT IS THE VALUE OF X HERE?
if you really want to make sure that x is not changed by f, declare it const. Sure, f can cast the constness away, but then again it could also walk up the stack in C and trash your stack frame anyway. It is UB in either case.

The typesystem in C++ can help protect against Murphy, but (unfortunately) not Machiavelli.

Re:Announcing Rust 1.22 by fredmorcos on Thursday November 23, 2017 @04:56AM (#15764047)
Agreed. But my example isn't about security or UB. It is about the language allowing you to write two IDENTICAL snippets of code that end up meaning two different things without any overloading involved. Like saying something and meaning something else.
Re:Announcing Rust 1.22 by gpderetta on Thursday November 23, 2017 @05:13AM (#15764115)

  int x[] = {5};
  f(x);
  // WHAT IS THE VALUE OF X HERE?
see, it works in C as well.
Re:Announcing Rust 1.22 by cesarb on Thursday November 23, 2017 @05:39AM (#15764205)
In C, the value of x in that fragment is still the same: a pointer (ok, not exactly, but something which behaves like a pointer) to a memory location where an int can be stored. The f(x) call can't change that pointer.
Re:Announcing Rust 1.22 by int_19h on Thursday November 23, 2017 @06:21AM (#15764364)
Try doing something like &x, and you'll see that it doesn't actually reliably behave like a pointer.
Re:Announcing Rust 1.22 by fredmorcos on Thursday November 23, 2017 @08:26AM (#15764873)
So you get my point. 'x' is not going to be modified behind your back and it's pretty clear on the calling site. In C++ it isn't clear.
Re:Announcing Rust 1.22 by gpderetta on Thursday November 23, 2017 @09:16AM (#15765171)
It is exactly the same between the two cases: the x object (either the array memory location or the integer memory location) can be changed by 'f' because mentioning the 'x' object name in a function call may implicitly converts to the address of the object, i.e. it passes by reference).
Re:Announcing Rust 1.22 by fredmorcos on Thursday November 23, 2017 @10:51AM (#15765757)
> can be changed by 'f' because mentioning the 'x' object name in a function call may implicitly converts to the address of the object

(1) They are two different types and (2) it's clear to you at the calling site!

Re:Announcing Rust 1.22 by pjmlp on Thursday November 23, 2017 @05:51AM (#15764255)
> And C, as opposed to C++, does not allow you to say something you don't mean.

More than 200 documented use cases of undefined behavior...

Re:Announcing Rust 1.22 by fredmorcos on Thursday November 23, 2017 @08:27AM (#15764881)
What does this have to do with syntactically expressing the same thing twice with two different semantic meanings?
Re:Announcing Rust 1.22 by pjmlp on Thursday November 23, 2017 @09:07AM (#15765117)
That C compilers decide for themselves to say things that the programmer did not intended to do in first place, thanks UB.
Re:Announcing Rust 1.22 by CyberDildonics on Friday November 24, 2017 @01:11PM (#15772157)
Unless of course f is a macro, then x could have been modified.