From a brief glance through the examples it looks pretty functional... is it basically a systems-ish scala?
From a brief glance through the examples it looks pretty functional... is it basically a systems-ish scala?
Dependency management with Cargo is hands down one of the best out there, it just works. The standard library continues to expand, but there are also many other external libraries you can find on crates.io.
> it looks pretty functional... is it basically a systems-ish scala?
I think it's better to compare Rust to ML languages family (OCaml, F#, and so on), as it was clearly influenced by it. It has many features you can find in ML languages - pattern matching, ADTs (algebraic types that are enums in Rust), and many other similarities.
Overall, the language feels very robust now, and I enjoy it much - it's a very decent replacement for C++, basically "C/C++ done right".
Hopefully you'll have a lot of fun with learning! :) Oh, and almost forgot: Rust community is one of the best that I've seen, so feel free to ask any questions on http://users.rust-lang.org - I'm sure there's a lot of people who'll be glad to help you.
If you want no dynamic dependencies whatsoever, then Rust supports linking to musl, which is an implementation of libc that's designed for static linking.
(Caveat: the lead designer of Rust's type system, Niko Matsakis, has done a fair bit of work with Scala, so there may be subtle influences.)
Agree! Sadly, they didn't use all the lessons Scala could offer them when designing their own language. :-(
Painful to watch as they introduce stuff where Scala developers already know that it's completely broken.
Allowing "return".
Mandating braces for functions and control flow constructs.
Rust iteration, which is both more limited and less safe (laziness) than the scala/ruby style of passing a closure.
> The cascade of efforts at error handling
You must be referring to ancient Rust with its condition system and such. Modern Rust code just uses Result types. > rather than getting on with higher-kinded types to allow
> them to do it right
Er, no, you don't need HKTs to "do it right", you'd just need HKTs to do it generically. Rust's error handling works fine for specific types; you can even write macros to emulate do-notation (and people have). > Allowing "return"
Welcome to the realities of imperative programming. :) Unlike Scala, Rust does not aspire to functional godhood. > Mandating braces for functions and control flow constructs
Scope in Rust is very, very important for expressing when references go out of scope and when resources are freed. Leaving scope implicit would be massively frustrating. > the scala/ruby style of passing a closure
Rust had internal iterators for years, and the entire `for` construct was based around them. They were removed because they were found wanting.As I've mentioned in a sibling comment, the lessons that Scala may have learned in its life do not necessarily apply to Rust. They are very, very different languages.
I would love higher kinded types, but most of our users are asking for other type system features first. What we've done doesn't preclude a HKT style in the future, as the signatures are the same.
I'm not aware of an imperative language that doesn't allow early returns, maybe there are some, but I find 'guard clauses' to significantly combat rightward drift.
Braces are to appeal to our core audience, who have been using braces and semicolons for decades. Absolutely, 100% subjective though, I know people who prefer the whitespace-based syntax, but you really only get one or the other.
> Rust iteration, which is both more limited and less safe (laziness) than the scala/ruby style of passing a closure.
I'm not sure specifically what you mean here, around both safety and closures.Here's Rust:
let v = vec![1, 2, 3];
let v1 = v.iter().map(|x| x + 1).collect()
Here's Ruby: v = [1, 2, 3]
v1= v.map {|x| x + 1 }
Other than the laziness, both are "pass a closure." And I'm not sure how safety ties in here at all.Most of these things seem like subjective preferences, rather than things that are "completely broken."
I think many users don't know that they want higher-kinded types, only that they want particular features.
> I'm not aware of an imperative language that doesn't allow early returns, maybe there are some, but I find 'guard clauses' to significantly combat rightward drift.
I don't know what you consider an "imperative language"; I'd consider Scala an example. I think a decent error mechanism (which Rust does have, even if the implementation is ad-hoc and reliant on a macro) provides a better way to express guard clauses. I think return is untenable in a language with lambdas, because any possible choice of semantics for return inside a lambda (including "compile error") will confuse a decent proportion of programmers.
> Braces are to appeal to our core audience, who have been using braces and semicolons for decades.
If by your core audience you mean C++ users then they're used to being able to omit braces on if/while/etc.
> Other than the laziness, both are "pass a closure."
I'm objecting to the .iter() part. Or perhaps more generally to the lack of something as extensible as do or for/yield. The for/yield construct turned out to be far more valuable to Scala than was realised initially.
> And I'm not sure how safety ties in here at all.
I meant unsafe in the colloquial sense. I think laziness makes programs very hard to reason about.
> Most of these things seem like subjective preferences, rather than things that are "completely broken."
I agree that they're not completely broken, but I think they're more than subjective; in many cases Scala has tried the various options over the years. We've tried exceptions and macros and found a better way of doing error handling. We've had return in the language and discovered it to be more trouble than it's worth. We've had a notoriously flexible syntax around function calls and seen a consensus on the best style develop over the years. We've seen some control-flow structures virtually wither away and others become indispensable.
Yield doesn't make a whole lot of sense in a systems language with machine-level control over stacks and allocation. It doesn't make a whole lot of sense in a systems language where the idea of jumping out of a stack frame either means doing strange low-level stack jumping tricks (defeating standard CPU/compiler optimizations) or allocating behind your back (which is something that Rust never does). Very early Rust actually tried using yield for iteration and it didn't work.
> We've tried exceptions and macros and found a better way of doing error handling. We've had return in the language and discovered it to be more trouble than it's worth.
We've experimented with these too. And I use return all the time in Rust. It's really useful and I would hate to see it go away.
I think Rust and Scala are just different languages. One's an applications language built on the JVM and the other is a low-level systems language with manual memory management. That difference means that different decisions may be appropriate.
Why? They could easily go to 2.x, no?
Python has had a lot of challenges with their changes from 2.x to 3.x, even though the language seems clearly improved. Much of the problem is converting popular existing libraries, which rely on a lot of donated time and effort. The Rust community is hoping to keep from being in a similar situation if at all possible.
See "What does it mean for Rust to be 1.0" in the release announcement: http://blog.rust-lang.org/2015/05/15/Rust-1.0.html
Stability Guarantee: http://blog.rust-lang.org/2014/10/30/Stability.html
This is because the compiler wasn't checking some cases strictly enough, and you could "hide" constraints from the compiler, causing them to fail to be enforced.
They checked against crates.io when raising this RFC, and found that there were 35 crates (packages) that would be able to keep compiling if this turned into a future-compat warning, to become an error in the release afterwards.
The example
trait Test {
fn test(&self) -> Option<Self>;
// ~~~~~~~~~~~~
// Incorrectly permitted before.
}
Should be trait Test: Sized {
fn test(&self) -> Option<Self>;
}
Because `Option<T>` requires that `T` be `Sized`.
Poking around on 1.3, I think that it would be an error to instantiate this trait with a [i8] or something that was not sized anyways, so you're not losing much by needing to declare the trait properly.To answer the question of why they don't bump the major version when soundness fixes break backcompat, it's because soundness bugs generally have implications for memory safety/undefined behavior, and it's assumed that people using Rust would prefer unsound code to break rather than to continue being potentially unsafe. Also, thanks to Crater, the Rust developers generally take it upon themselves to file patches with third-party crates to update them such that the package developers themselves are (ideally) neither blindsided nor inconvenienced.