News for hackers. Stuff that matters.
Re:Thoughts on Rust, a few thousand lines in by dkarl on Wednesday January 09, 2019 @05:00PM (#18869401)

    let foo = "...";
    let foo = parse(foo);
    let foo = escaped(foo);
    ...
    doSomethingWith(foo);
I don't see how this is helpful for avoiding the bug described. The most common bug with this type of code is mistaking which form "foo" represents at a given line of code, or that form changing as the code evolves. For example, if one programmer writes

    let foo = "...";
    let foo = parse(foo);
    ...
    doBarWithFoo(foo);
and another programmer comes along, doesn't notice the call to doBarWithFoo, and needs an escaped version of foo:

    let foo = "...";
    let foo = parse(foo);
    ...
    let foo = escaped(foo);
    doBazWithFoo(foo);
    ...
    doBarWithFoo(foo); // This still looks correct in isolation
This is a classic problem with mutable variables that frequently causes hard-to-spot bugs. Whereas if each form has a distinct meaningful name, this change wouldn't introduce a bug, and if somehow a bug were introduced, good names will make it possible to spot even considering the line in isolation:

    doBarWithFoo(fooEscaped);  // Hey!  The input to doBarWithFoo shouldn't be escaped!
If the only useful form of foo is the final one, then you can avoid having accessible names for the invalid intermediate forms like this:

    let foo = escaped(parsed("..."));
Or like this for more complicated logic (I'm not a Rust programmer (yet) so this may not be the right syntax):

    let foo = {
        // Complicated logic
        finalForm;
    };
I feel like if I ever write a lot of code in Rust I'll find a linter rule that warns about shadowing variables and use it religiously. But maybe I'm missing a use case where it's crucial.
Re:Thoughts on Rust, a few thousand lines in by Misdicorl on Wednesday January 09, 2019 @05:31PM (#18869681)
I believe the way this is solved is by having the type of escaped(foo) different than that of parse(foo) and only accepting a EscapedString in doBaz and an ParsedString in doBar.

Your type structure at no extra runtime cost is String : ParsedString : EscapedString.

This ensures you don't escape strings before parsing them too. Nice!

Re:Thoughts on Rust, a few thousand lines in by afraca on Thursday January 10, 2019 @03:49AM (#18872468)
This is common in Haskell as well using `newtype`. You can have type aliases like

  type A = B
but you can use the following function with a B:

  f :: A -> _
whereas

  newtype EscapedString = EscapedString String
  f' :: EscapedString -> _
would prevent from using f' with the wrong data. Newtype is a zero-cost abstraction.
Re:Thoughts on Rust, a few thousand lines in by wilg on Wednesday January 09, 2019 @05:30PM (#18869671)
I think the example only really works if `parse` and `escaped` return something other than a string. If that was the case, the type system will save you.
Re:Thoughts on Rust, a few thousand lines in by moosingin3space on Wednesday January 09, 2019 @05:31PM (#18869680)
In your particular example, the ownership system would help here, since `foo` is consumed by `doBazWithFoo`. (Only exception is when `foo` is `Copy`.)