News for hackers. Stuff that matters.
Re:Mrustc: a Rust compiler written in C++ by kibwen on Thursday September 21, 2017 @05:58PM (#15307703)
This was recently posted to /r/rust with the engagement of the author (mutabah) if you'd like to ask questions or get involved. In particular here's him answering why he started this project: https://www.reddit.com/r/rust/comments/718gbh/mrustc_alterna...

One of the interesting things about this project is that because its initial goal is to validate the reproducibility of the main Rust compiler it doesn't actually need to implement a borrow checker, as the borrow checker strictly rejects programs and has no role in code generation.

Re:Mrustc: a Rust compiler written in C++ by tom_mellior on Friday September 22, 2017 @07:36AM (#15311182)
> it doesn't actually need to implement a borrow checker

I was under the impression that Rust's lifetime and ownership system is not just used to ensure safety, but also for knowing where the compiler should insert deallocation code for dynamically allocated objects at the end of their lifetimes. Is that not the case? Does mrustc generate code that leaks memory, or is there enough information in the Rust source code to do precise deallocation even without a borrow checker?

Re:Mrustc: a Rust compiler written in C++ by Thiez on Friday September 22, 2017 @08:07AM (#15311384)
That is not the case. Destructors run for things that go out of scope. When you create a reference to something ("borrowing") that reference is associated with a lifetime. This lifetime represents how long the reference is valid. A reference can never outlive the things it references (or it would be a dangling pointer), but the opposite is not true: you can create a reference with a lifetime that is shorter than the thing it references.

So basically lifetimes are used only by the borrow checker for intelligent linting. Once the borrow checker is done, the compiler loses interest in lifetimes entirely, and they don't affect codegen.

Re:Mrustc: a Rust compiler written in C++ by eddyb on Friday September 22, 2017 @08:03AM (#15311350)
Destructor scopes are determined from syntactical rules and lifetimes don't play any role in them. OTOH, lifetimes are restricted by the shape of the destructor scopes.
Re:Mrustc: a Rust compiler written in C++ by grok2 on Thursday September 21, 2017 @10:10PM (#15308922)
If you don't really need the borrow checker to compile Rust, can the original Rust compiler have a mode where it doesn't do the borrow checking? That might make it easier to ease into Rust, because right now, "fighting" the borrow-checker is the hardest problem with learning Rust.
Re:Mrustc: a Rust compiler written in C++ by kibwen on Thursday September 21, 2017 @11:46PM (#15309261)
Be careful not to underestimate the failure mode of trying to compile arbitrary Rust code without the borrow checker. It appears that your goal is to let people "ease into Rust" by trading compilation errors for runtime segfaults, but it's just as likely that un-borrow-checked Rust code could produce malformed LLVM IR that will cause totally unpredictable compile-time failures in LLVM with indecipherably cryptic error messages.
Re:Mrustc: a Rust compiler written in C++ by grok2 on Friday September 22, 2017 @02:40AM (#15309886)
That really wasn't my intention -- it mostly makes sense to use Rust for the borrow checker. Instead my only intention was that it simplify the process of learning Rust -- using all it's features (except the borrow checker), getting a working program fast and have some easy wins when learning Rust without stumbling constantly over the borrow checker. Maybe production mode could always enable the borrow checker.
Re:Mrustc: a Rust compiler written in C++ by Manishearth on Friday September 22, 2017 @03:43AM (#15310133)
When folks complain about the "borrow checker" usually they're complaining about a superset of features including move semantics and how data works in Rust. This is far more deeply tied into the whole model of Rust and is frankly very core to the language, "turning it off" won't make it easier to learn, it will make it easier to learn a completely different language.

Besides, all of this is necessary for soundness. Turning off the borrow checker won't magically get you a compiler that is less permissive, it will get you a compiler that will very likely produce nonsense if your program would have failed the borrow checker had it been present.

Re:Mrustc: a Rust compiler written in C++ by Lorkki on Friday September 22, 2017 @02:52AM (#15309941)
The need for the borrow checker is driven by Rust's chosen resource management model. It sounds like what you really want is an optional mode with garbage collection, in which case I recommend you check out F#.
Re:Mrustc: a Rust compiler written in C++ by vog on Friday September 22, 2017 @04:29AM (#15310300)
... or the "original", OCaml, from which Rust was heavily inspired.
Re:Mrustc: a Rust compiler written in C++ by sitkack on Friday September 22, 2017 @06:19AM (#15310727)
Re:Mrustc: a Rust compiler written in C++ by thrasibule on Friday September 22, 2017 @09:36AM (#15312019)
F# is not a superset of OCaml. There are many things in OCaml that are not in F#. The second link you pointed out lists them.
Re:Mrustc: a Rust compiler written in C++ by gnuvince on Friday September 22, 2017 @06:17AM (#15310705)
This is akin to suggesting that learning Java could be simplified by making its type system optional. Also, if one could turn off safety features, why would they ever switch them back on? They learned a different language, one where those checks are not present.
Re:Mrustc: a Rust compiler written in C++ by ptx on Friday September 22, 2017 @04:32AM (#15310314)
You still need the borrow checker, and this compiler won't change the kinds of programs you can write. It only works on programs that pass the borrow checker, just like the regular compiler, the difference being that it doesn't check that the program is valid (i.e. passes the checker) but assumes that its validity has already been checked earlier by the regular compiler.

If you give an invalid program to the regular compiler it will be rejected, but if you give the same program to this compiler it might produce nonsense. So the developer of a program would feed it to the regular compiler for checking, but others could take the finished release of the program, assume that it's valid and feed it to this compiler instead, as I understand it.

Re:Mrustc: a Rust compiler written in C++ by Sharlin on Friday September 22, 2017 @06:54AM (#15310954)
OTOH that's already the case with C and C++ where the compiler is allowed to assume undefined behavior cannot happen.
Re:Mrustc: a Rust compiler written in C++ by steveklabnik on Thursday September 21, 2017 @10:14PM (#15308941)
The borrow checker is needed for soundness; this means mrustc will miscompile things.

Assuming the input is sound, mrustc will do the right thing. Ignoring the borrow checker will not make things magically work.

Re:Mrustc: a Rust compiler written in C++ by keeperofdakeys on Thursday September 21, 2017 @11:23PM (#15309192)
Removing the borrow checker would allow you to compile broken code (eg. use after free, data races). However given code that compiles on rustc - passes the borrow checker - you don't need to reverify the borrow checking to get correct code from mrustc.
Re:Mrustc: a Rust compiler written in C++ by banachtarski on Friday September 22, 2017 @02:33AM (#15309856)
(note, not the OP) Yea but by the same token, the borrow checker prevents me from doing perfectly valid logic and is frustrating in its own right.
Re:Mrustc: a Rust compiler written in C++ by moomin on Friday September 22, 2017 @03:28AM (#15310083)
That's true of literally all compile time validation.
Re:Mrustc: a Rust compiler written in C++ by banachtarski on Saturday September 23, 2017 @05:22AM (#15318933)
No I'm not saying I have an issue with compile time validation. Far from it.

My point is that the borrow checker is explicitly meant to protect against data races and such. There are situations where I write code I can prove does not violate any hazards but Rust's "validation" is overly-zealous.

Re:Mrustc: a Rust compiler written in C++ by steveklabnik on Saturday September 23, 2017 @12:49PM (#15320530)
Which ones do you run into most often?
Re:Mrustc: a Rust compiler written in C++ by weberc2 on Friday September 22, 2017 @10:53AM (#15312696)
But its more true of some than others.
Re:Mrustc: a Rust compiler written in C++ by keeperofdakeys on Friday September 22, 2017 @06:33AM (#15310810)
Yes, some valid code won't pass the borrow checker. But at the same time, far more invalid code doesn't pass it. Personally I see it as a tool to help me reduce possible runtime errors, and instead have them as compile time errors. This does mean that I often need to design my program around it, but that's try of basically every other language.

The few times I do have an issue I'm usually writing FFI code to interact with C, and I try to minimise that code as much as possible.

Re:Mrustc: a Rust compiler written in C++ by tmzt on Friday September 22, 2017 @08:51AM (#15311679)
And of course in Rust, if you Try you might get an Ok Result, or you may just return in Err.

It's often a good exercise to craft your program to the language you're targetting, to take advantage of it's strengths or embrace it's traditions.

Re:Mrustc: a Rust compiler written in C++ by angelsl on Friday September 22, 2017 @02:49AM (#15309925)
There are probably assumptions/invariants built into how rustc generates LLVM IR that you will have to guarantee are met if borrowck is disabled.

Do you really want that?

Re:Mrustc: a Rust compiler written in C++ by Ygg2 on Friday September 22, 2017 @10:17AM (#15312358)
Similarily, I like Haskell, but find it's syntax and the whole function and currying thing confusing. Can't I just write Haskell without HKT, functions and currying?

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

Jokes, aside, if you aren't there for Rust borrow-checker, then I wonder, do you really need Rust at all?

Re:Mrustc: a Rust compiler written in C++ by __s on Thursday September 21, 2017 @10:18PM (#15308960)
Learning Rust without borrowck is throwing the baby out with the bath water
Re:Mrustc: a Rust compiler written in C++ by nickrio on Thursday September 21, 2017 @10:27PM (#15308999)
How about "throwing the baby out but keeps the bath water"?

Which is more appropriate for this scene I think.

LOL

Re:Mrustc: a Rust compiler written in C++ by weberc2 on Friday September 22, 2017 @10:45AM (#15312621)
I never understand this. I don't mind the borrow checker, I mind the affine type system. It really bugs me that I can't pass the same String into two functions in series, or why preventing that would be a desirable language property.
Re:Mrustc: a Rust compiler written in C++ by kiriakasis on Friday September 22, 2017 @03:16PM (#15314938)
IIRC because the first function could deallocate it.
Re:Mrustc: a Rust compiler written in C++ by weberc2 on Friday September 22, 2017 @03:50PM (#15315203)
Seems like explicitly freeing memory should be regarded as unsafe. Unsafe things aside, the compiler should regard it as a copy instead of a move so multiple functions can safely use the resource without having to pass it by reference. If there is a good reason for an affine type system, I suspect it has to do with parallelism and not manual memory management.
Re:Mrustc: a Rust compiler written in C++ by dbaupp on Sunday September 24, 2017 @04:26AM (#15323875)
Your suspicion is wrong. It has benefits for parallelism, but is critical for ensuring safety of the more predictable (vs GC) Rust/C++ style of "manual" memory management.

When one doesn't have a pervasive GC to dynamically clean things up, things still need to be freed but have to be freed in static locations (either explicit free calls in C or end of scopes in Rust and C++). Making this safe means defending against pointers becoming dangling which Rust does by restricting mutation. This restriction translates into some things that can't be copied, such as mutable references (that can lead to iterator invalidation and use after free, among every other undefined behaviour).

In other words, explicit/scope-based freeing being unsafe means the only way to safely manage memory is a garbage collector (tracing or reference counting), which limits how many programs can be written that are verified-safe by a computer. I believe Ada takes the approach you suggest, but this limits it to be most useful for programs that don't allocate (or only do O(1) allocation during startup).

Affineness also allows modeling things like session types better, letting programmers construct their own APIs that defend against mistakes.

You could, and people have, argue that some types could be "autoclone", as in, have `clone` calls automatically inserted where necessary, but when it is raised, a lot of people express dislike because they feel it will encourage slow code and mean people aren't guided towards the (usually) better solution of using references.

Re:Mrustc: a Rust compiler written in C++ by weberc2 on Sunday September 24, 2017 @11:48AM (#15325123)
I understand not copying mutable pointers; I don't understand preventing copies of pointers to immutable data. I also don't see why affine types allow rust to get away without a GC in a way that scoped-based memory doesn't.
Re:Mrustc: a Rust compiler written in C++ by steveklabnik on Sunday September 24, 2017 @03:44PM (#15326170)
&T is Copy, so I'm not sure what you mean with the first bit.

For the second one, consider Box<T> vs uniq_ptr<T>; Rust can statically prevent use after-move, C++ cannot, and you'll get a NPE. That is, you can totally get rid of a GC through only RAII, but you can't guarantee memory safety (as far as we know!) without affine/linear types.

Re:Mrustc: a Rust compiler written in C++ by dbaupp on Monday September 25, 2017 @08:58PM (#15335378)
To be clear, Rust does scope-based memory management and does allow copying pointers to immutable data.

Affine typing (plus the rest of Rust's system) on top of scoped memory management is needed to avoid problems like returning a pointers into something that is deallocated at the end of a function:

  int &foo() {
    std::vector<int> v = ...;
    return v[0];
  } // return value is dangling
And similarly, avoiding having pointers into things that are destroyed when their parent is modified:

  std::vector<std::unique_ptr<int>> v = ...;
  int &ref = *v[0];
  v.clear();
  // ref is dangling