Some things D has that Rust doesn't: compiler-checked function purity annotations, higher-kinded types, variadic functions/generics, types parameterised by numbers, compile-time function evaluation, mixins, a fast compiler (the reference DMD compiler), powerful and convenient compile-time reflection (I think technically Rust can do anything D can at compile time, but it requires writing a syntax extension to do so). For better or worse, D also has classical OO inheritance, which Rust lacks.
I would say this is fairly accurate, yeah. We got rid of purity in Rust, we didn't find it useful. HKT, variadic generics, and type-level integers are all things we want to do in the future.
The ship's probably sailed on this, but is there any chance of Rust getting a module system like OCaml's (or Haskell's upcoming Backpack) in future? Or is there a way to provide module signatures with the current module system?
Never say never, but I'm not aware of anyone who's even working on thinking about suggesting it. That'd be step one, creating an RFC which thinks through the design.
Rust and D are both great. The difference is that Rust has a hugely powerful hype train, which happens to be operating at 1,000% capacity somehow since the beginning of Rust.
Rust inherited the enthusiasm of some very prominent and outspoken members of the Ruby community. These ex-Rubyists honed the craft of projecting excitement with Ruby and RoR, and brought these skills and talents with them when they moved to the Rust camp. The D camp hasn't really had anyone like that join them.
I have to agree on this. I was surprised to see that a majority of the Rust community actually comes from some web-development domains. Especially when comparing Ruby, a highly flexible dynamic language, to Rust a language full of constraints (for its own valid reasons).
Note that the a hype train is a two-edged sword, it will both bring a strong community and might also induce a cliff with the other communities (praising a single god is never a good thing).
An alternative interpretation might be that rust has particular appeal to those that primarily use dynamic languages. It's probably both, but I will say that as someone that's busy getting stuff done in Perl[1] every day, rust looks appealing, and a lot of that has to do with guarantees. If I'm going to give up the convenience of Perl for a lower level language[2], I need to be sold. Rust's promise of provably correct memory management sounds really good in that situation.
1: I've used lower level languages, but for nothing large, and I haven't started a project in C, C++ or even Java in over a decade, and was never very enamored.
As someone who fits this mould, for me, it's not exactly that. Yes, in my professional life, people know me for my Rails work, but I learned C at a very young age, and while my systems-level stuff was a bit out of practice, for me, Rust is a _return_ to the kind of stuff I used to do earlier in life.
Oh, and I'm not sure "majority" is really true. Yeah, maybe some of us have disproportionate impact, but a very large number of people in Rust-land really know their systems stuff. I am humbled to work alongside such talented people.
As someone who's been following the hype, but not really jumped on yet, the difference (whether real or imagined) seems to be that rust is trying to do something new, and D looks to be (and I've seen it aggressively marketed as) C++ with some better choices and cool features. Personally, I'm not really interested in C++, but I am interested in getting for familiar with a systems language, so rust interests me.
From what I understand, the only new thing Rust is contributing is managed lifetimes. Everything else is, like in D, just borrowed from other languages and put together.
That said, I've mostly heard that lifetimes are still too young to be worth the trouble. So the one new thing Rust does bring to the table isn't really ready yet.
I think of it like this: If I'm going to manually be managing memory, I might as well get some real gain for that effort. Provably correct memory management through an ownership system sounds like it might be worth the effort, especially if it might also help in situations with threading. I've had reason to use threads quite a bit in the past.
> That said, I've mostly heard that lifetimes are still too young to be worth the trouble. So the one new thing Rust does bring to the table isn't really ready yet.
Not in my experience. I wrote tons of safe Rust every day and I really enjoy not having to worry about difficult-to-debug crashes, undefined behavior, and security problems.
> just borrowed from other languages and put together.
Most of these things are new to the systems space, though. Things like algebraic data types, etc. Also usable affine types.
> lifetimes are still too young to be worth the trouble.
I've heard pretty much the opposite. Firstly, nobody who uses Rust calls the feature "lifetimes" (it's usually called borrowing or borrow checking). That's the name of the syntax, and while the syntax is new and somewhat confusing it doesn't pop up that much thanks to elision.
Borrowing has a learning curve, yes. But really, it's an equivalent set of principles to what you would do in C++ to keep your pointers safe. The difference is that you can write small C++ codebases without worrying about "C++ borrowing", whereas you need to think about these things off the bat in Rust.
D's new things have been more accidental than by design... and kinda subtle too. Like the compile time reflection. I'm sure someone else has done it somewhere before, but D makes it really easy.
I think I'm climbing aboard the hype train. The thing that made a difference for me was the lack of GC. I knew I could have an easier time selling that to my team than GC. As soon as they hear 'GC' they will probably start to think of unacceptable latencies and lump D in with Java, Python (et al).
That said, D's compatibility with C++ is a big plus.
On the nontechnical side I would add that since D is a lot older, keeping up with changes is a whole lot less challenging. Its stable enough that one can put it near the money without worrying too much about breaking changes.
My impression is that things are settling down now, but I've encountered quite a few rust code bases that required "latest rust" (latest > 1.0) - and even "nightly".
Not to say that rust-the-language hasn't stabilized, but I think the point about D being (way) more mature still stands?
(Note, it's a good thing that people are writing code to test/work with/exercise latest rust/nightly etc -- but just because I can be fairly sure code I write today will compile tomorrow (which is good!) -- that doesn't mean "all of rust land" is stable).
Please don't take this of critique of all the hard work going into rust -- the only way this wouldn't be a thing was if rust core was a dead project.
[ed: To add to that - it might well be that all of the projects I've seen lately where I've had to wake up multirust[1] and do a little dance before my beautiful random code from random person on the Internet have been willing to compile -- have all been bad samples of rust code - but they're still part of the landscape of rust code one encounters in the wild.
[1] https://github.com/brson/multirust (eats a bit of space (~200MB per version of the compiler/toolchain) - but in my very limited testing works nicely!)]
> quite a few rust code bases that required "latest rust" (latest > 1.0) - and even "nightly".
In my experience most of these either use old features which have a stable counterpart, or use compile-time codegen (there are stable libraries to do this now, though they aren't as ergonomic as plugging into the compiler directly)
Yeah, I mean, I don't take this as a critique, it's the same for basically every language. When you build a project with a new version, you might take advantage of the new features. Such is life. :)
GP is actually the second post in a week I've seen where someone mentions tracking rust changes, but rust has been 1.0 for a while now. Have there actually any backwards incompatible changes since 1.0, or are people really complaining about a problem that's been fixed for close to six months and even then was specific to beta versions?
There haven't been backwards-incompatible changes in practice, no.
That is to say: there have been technically backwards-incompatible changes, but every compiler and language, including those of C++ and Java, make technically backwards-incompatible changes in point releases (e.g. defining new functions in the libraries and modifying undefined behavior). Rust doesn't make changes that violate the stability guarantee. It goes further than that, in fact—any change that is not breaking according to the public guidelines but is thought possibly breaking in practice is tested against crates.io and feedback is solicited from those who have any private crates that might be affected to make sure it doesn't break them either.
(Unfortunately this policy is often misunderstood—for example, it's been claimed that Rust will make breaking changes as long as they don't break anything on crates.io, which is very much not an accurate description of it.)
Due to its erratic development and the much-delayed release of Rust 1.0, I fear that many people have associated Rust with frequent breaking changes, even if that is no longer the case. It's much like the "Java is slow" fallacy; it may have been true in Java's very early days, but it hasn't been the case for many, many years. Yet the misconception still persists, even to this day. This is the sort of taint that a language will find very hard to shake. The "Rust suffers from breaking changes" misconception is very ingrained in the minds of many programmers now.
Well, not really. Higher-kinded type parameters are something that requires a kind (typeclass) system in the first place, which D intentionally doesn't have (as D's authors are opposed in principle).
Yeah, I shouldn't have made it read like I was equating the two. What HKT means is that typeclasses, like Monad, can take parameters of higher kinds. But if you don't have typeclasses in the first place (like D doesn't), then you don't have HKT.
I'm referring to what people want when they say they want "higher-kinded types" in Rust. That is: the ability to have typeclasses with higher-kinded type parameters.
I'm well aware that the formal definition of an HKT is just a type with a higher kind, and that's irrelevant to this discussion.
I disagree. D is an improved C that does a lot of the same things as C++, but in order for it to be a better C++, it would need to start with C++ as a foundation and build on it. D has more of a scripting language feel to me.
I'm curious about this, although I don't think this is the first time I've heard D described as having a script-y feel to it. It sounds along the same lines as people describing Go as almost a scripting language, or comparing it to them. Neither Go nor D seem especially dynamic, both have compilers for reference implementations, both look more like C than Python. (To my eyes at least; I've never tried either one. Thus this question.)
Is it primarily the speed of the compilers? Both DMD and g6/g7/g8 boast very fast compiles, and Go uses somewhat script-y tools... but #!/usr/local/bin/tcc -run hasn't changed C's reputation. Fast compiling and memory safety, maybe?
People often say this because D has many features that allow it to be almost as flexible as the various scripting languages while still being compiled and statically typed. I don't bother with bash/cmd nowadays as D can easily fill that role, with the bonus of my small little scripts having all the power and scalability that D offers.
C translates almost 1:1 to Rust, but when converting C++ to Rust you'll run into impedance mismatch between OO hierarchies and traits, and generics being narrower in functionality than templates.
In Rust you still can do "clever" things with generics to make them feel like C++, but the rest of the language is still closer to C: errors returned rather than thrown, no inheritance (but the "flat" OO and enums map well to what OO-like C programs do with "handles"), no constructors, etc.
Having errors on return has merits. Particularly it make error handling more deterministic. What it tends to do though, in languages like C and Go, is be very verbose.
Rust largely mitigates that through judicious usage of some of its higher levels features. Specifically its try! macro wrap up the common case of passing errors up the call stack quite neatly. With that and the pervasive RAII, Rust does a pretty good job of making error management quite unobtrusive.
It also has quite a nice way of converting errors types using traits that, in my opinion at least, handles typed error propagation better than most exception mechanisms I am familiar with.
From a personal pov, I like the determinism and I like the type conversion. I probably prefer D's scope mechanism to RAII in general as I like thinks to be as explicit as possibly but without being too verbose. But I think Rust seems to have hit quite a nice balance.
No. There's a few things that combine to make it different, but what it really boils down to are enums. Rust functions that can fail return a type, Result: http://doc.rust-lang.org/std/result/enum.Result.html
There's a number of things that make using this ergonomic: you can use the try! macro to convert it to a success value, returning an error value up the stack. You can use any of the combination methods on that page to chain various possibly-failing functions together into something that looks nice. Some people even use the word "monadic." We don't have if checks everywhere.
I think it's more about Rust's approach to OO. In Rust, traits are usually used as interfaces for generics instead of dynamic dispatch. The generated code/performance is more like what you would get if you implemented them explicitly for each appropriate type in C, built around structs. You could do this with C++ templates, but it would be a huge pain in that language due to lack of template type safety.
This is a quite important part of Rust (IMHO) because it gives the language a performance profile closer to C than C++ in many instances.
Hmm, I see your point, but I've found that even in template-heavy code the compiler can produce code that's pretty optimal. Are you saying that with Rust it is easier to fall into the pit of success, as it were -- requiring less reasoning about how a compiler might convert the [templated|generic] code optimally?
My point was not that Rust creates better template code, but that a lot of things one uses dynamic dispatch for in C++ use templates instead. There are plenty of times when one knows the full derived type of a class in C++, but one throws away that information virtual calls are used anyway.
I think this is because Rust makes it far easier to use generics; they're type-safe and don't need to be pushed to header files. Also, the coding culture around Rust pushes one to use enums for dynamic dispatch instead of "trait objects" (Rust's equivalent of VFTs).
With the mythical smart enough compiler with god like devirtualizer it would be less of an issue but gratuitous use of virtuals annoys me no end. CRTP isn't that hard for the simple use cases but you are beholden to the god of compiler error messages when things go wrong. One great thing that clang has done (among others) is make g++ get their shit together. Contrary to the popular sentiment I personally find the current crop of g++ error messages more helpful.
While OOP is perfectly possible in Rust, IMHO it is a lot more like doing OOP in C than in C++ (despite nice features like traits and generics).
Rust is marketed as a "general-purpose, multi-paradigm, compiled programming language" and D "originated as a re-engineering of C++", so may be I'm biased by my interpretation of the goals from both language designers.
You could use it as a starting point, but it was never intended to be a generic tool. For example, the C++ code was changed in some places to make the job for the translator easier.