I haven't read up a lot on Rust but I feel that it is similar to Go and perhaps Ceylon. Can someone explain why there is a sudden "renaissance" in such memory-managed systems programming languages?
Edit: Oh, and also the D programming language. There are quite a few of these!
Rust seems a different level of complicated to Go. Go seems quite minimalist. Rust seems more like it's trying to include the essentials of everything, but in as concise a fashion as possible.
That's a good way of putting it (although perhaps "everything" is too strong a word -- we don't want to build every paradigm imaginable into the language).
When in doubt regarding features, I tend to ask myself "would a next-generation browser engine need this language feature to be more secure/more maintainable/faster than current browsers?" (That's not to say that we're building the language only for a browser engine, but I think it's useful to have a target use case in mind when designing a language.)
Go was developed by guys who prefer C to C++, Rust was developed by guys who were fully immersed in a complex "modern C++" code base.. and it shows.
Go reminds me a lot of C as far as the look and feel is concerned. Go code is usually readable and straightforward, simply because Go (like C) deliberately limited the number of language constructs.
In contrast, Rust looks like a re-invention of modern C++.
I mean, C++ is much more popular than C for application development so that might not be a bad thing. However, I admit being in the C/Go camp of "build complex things out of a few simple building blocks" vs. the C++/Rust camp of "build complex things out of complex things".
As I've said earlier, we talk about how to minimize language complexity nearly every day. I would be thrilled if we could remove enough features to make Rust's spec as short as Go's.
That said, I think Rust is going to be somewhat more complex than Go because our needs are different (particularly around safety and memory management).
If you do see ways to simplify the language, we'd like to hear about them.
For me, the killer feature of Rust is the support for RAII and explicit, deterministic memory management (if you want it).
RAII and the ability to deterministically manage resources has always been C++'s killer feature IMHO.
There have been lots of improvements that could be made to C++ once you were willing to eliminate backwards compatibility - but all of the options up to now (e.g. D, Go), forced a GC on you, with no language support for explicit resource management.
I'm very pleased with direction "Rust" seems to be taking in this respect.
"but all of the options up to now (e.g. D, Go), forced a GC on you, with no language support for explicit resource management."
That's a lie. D supports both RAII(via scope stament which is a lot more flexible that C++ approach as well as using structs) and deterministic memory management.
"That's a lie." -> it's been a while since I looked at D so maybe it's changed since I last looked - but I remain unconvinced that the GC in D will deterministically call your destructors for you (which is my point) and runs in the same thread.
As I understand it, the Rust GC uses reference counting precisely for this reason. To be honest, I'd be happy even if it did not detect cyclic references as I never found these to be a problem when writing C++ code (could always re-factor to avoid them).
Maybe I should have said "deterministic destruction by the GC" instead of RAII.
Whatever, my intention was not to mislead. Please don't call me a liar just because you disagree with something I state with honest intentions.
How about RAII in Go in the form of a keyword that indicates an object can only be allocated on the stack? (Channels and goroutines would wreak havoc with that, unless these objects were passed by copying, or the compiler would just tell you that's forbidden)
I'm not sure of Go's support for RAII... the key feature is the "composability" of the RAII technique.
In C++, I can embedded a "socket" class as a member of some other object - on the stack or the heap - and it automatically and implicitly gets cleaned up correctly and deterministically, whether or not an exception is thrown, without me having to write any extra boilerplate.... so long as I follow the "rules" (and this is one of the places where C++ could be improved on).
"try/finally" or some sort of "stack-only" annotation doesn't really cut it for creating new resourceful objects out of existing ones.
For example, C# has the "using" syntax and also supports try/finally - these let you write code that works with anything that implements "IDisposable".
It handles the trivial cases - but as soon as you start wanting to compose together IDisposable instances you end up having to write lots of your own boilerplate to deal with propagating the "dispose" methods and ensuring that everything works correctly if an exception is thrown.
Of course, writing and testing all of the edge cases is very tedious and often difficult because you are dealing with resources like sockets and database connections after all - so even "mocking" them becomes hard.
Because its so difficult, most people just end up writing C# code that leaks resources (but not memory).
the key feature is the "composability" of the RAII technique.
I think it might be possible to have composability in RAII in Go if such objects weren't allowed to live anywhere but the stack. (Which would limit passing through channels.) Those objects would have a well defined creation and destruction time. While not completely universal, this might still be quite powerful and useful.
It would. (In fact, you might be able to do this today with runtime.SetFinalizer.)
You do have to be careful to avoid bringing back the objects that your finalizer references from the grave. If you do that in Go and create cycles, it leaks (which isn't unique to Go, many other languages do this). You need a sophisticated GC (like Java's) or a type system that's aware of the heap/stack distinction of objects (like Rust's) to mitigate that.
I suspect that the advent of light-weight virtualisation and sandboxing (LXC, seccomp, NaCl) allows language implementors to provide the interesting properties of Java — security and ease of deployment — without being barred from compilation to native code. That only applies to Rust and Go, Ceylon is a JVM language and D has been around since 2001; also Rust and Go are quite different languages, even in the memory department.
Edit: Oh, and also the D programming language. There are quite a few of these!