
Some notes on Rust - wkornewald
http://lambda-the-ultimate.org/node/5113
======
nercury
> Nobody seems be saying much about Rust, or if they are, the LtU search can't
> find it. So I'm starting a Rust topic.

The reason I personally am silent about it is because there is an ongoing
overhaul of standard io libraries. Honestly, my need to be adventurous dried
up when I was left with few broken libs. Writing about Rust still has a risk
of becoming obsolete and misleading quickly. Waiting for the _real_ 1.0.

------
frou_dh
> There's a macro called "try!(e)", which, if e returns a None value, returns
> from the enclosing function via a return you can't see in the source code.
> Such hidden returns are troubling.

Strikes me as simply a very appropriate use of macros. Get tired of writing
the same syntactic fragment again and again? Write a macro. Want to see what
some macro is "hiding"? Look it up or expand it.

~~~
ajanuary
The issue is it makes it difficult to notice that a function might return when
scanning through a function. Especially as it's in places that are looking for
a value (e.g. assignment).

At the moment it's just return and try!, but people look to the standard
library for what is acceptable. When the standard library contains a macro
that can return, people will write their own macros that return. It could
potentially be half a dozen different macros you need to keep in your head.

Personally, I go back and forth on it. Hopefully it will turn out fine.

~~~
deathanatos
> The issue is it makes it difficult to notice that a function might return
> when scanning through a function.

What other solutions are there? The only other approach to error handling I've
seen is exceptions (e.g., C++, Java, C#, JS…), and if you don't like `try!`
because it is a "hidden return", you certainly won't like exceptions. At least
with Rust's macros, I know that in the absence of one, there is no return; in
the presence, there might be. Exceptions in most languages make no guarantee.

~~~
ajanuary
It's a trade off. For the trouble of exceptions I get nice benefits like stack
traces (though there are proposals to add stack traces to Rusts error
handling). There are times when I really like exceptions, and times (such as
trying to trace through an execution path) that I'm irritated by them.

What other solutions are there? Well, you could make the return explicit:

    
    
        let z = try!(x / y, onerror = return)
    

There are obvious downsides, such as added verbosity, and the need to figure
out keyword arguments in macros, and do you allow access to the error value
etc. but at least I can grep for/highlight "return". It also makes the meaning
of the slightly confusingly named "try" more obvious (again, I'm vaguely aware
of proposals that would change the name).

I think ultimately try! is a good thing, but I don't think it's trivially "a
very appropriate use of macros". It's a considered use given some difficult
trade-offs.

------
gcv
Rust's error handling looks like the Maybe monad. That seems pretty reasonable
in Haskell. I'm a little surprised by the criticism in the article — is the
author saying there isn't enough syntactic sugar?

~~~
falcolas
My experience mirrors the author's: it results in a lot of use of macros and
case statements. These create a fair bit of cognitive overhead to discern what
the program flow will end up being, and special syntax for unpacking values.

The broad use of case statements leads to one more odd problem - knowing when,
and when not, to use a `;`. Explicit returns are frowned upon, they prefer the
"results from the last expression" form of returns. The `;` results in an
expression returning a different value and a different type. The type system
will usually catch these errors and print a helpful "perhaps you should remove
the ';' from this line" message, but it's an extra bit of cognitive overhead
induced by case statements.

Ultimately, I think it's less about missing syntactic sugar, and more about
the type system acting like an electric fence instead of a hedge in its
efforts to guide the user to their destination.

~~~
burntsushi
Explicit returns are not frowned upon. I don't know where you got that idea.
The only thing I can think is that this:

    
    
        fn foo() -> bool {
            true
        }
    

is preferred over

    
    
        fn foo() -> bool {
            return true
        }
    

But that's more of a style issue.

As for `;`, it's just like Standard ML. `;` is for sequencing expressions. I
love it.

~~~
falcolas
> Explicit returns are not frowned upon. I don't know where you got that idea

From the docs:

[http://doc.rust-lang.org/book/functions.html](http://doc.rust-
lang.org/book/functions.html)

> Using a `return` as the last line of a function works, but is considered
> poor style

~~~
burntsushi
Yes. Which is what I said. "Using a `return` as the last line of a function
works" is not the same as "don't use explicit returns."

~~~
falcolas
So I should use `return` except when I shouldn't? This is the cognitive
overhead problem I'm talking about.

The original context of my concern is the instance where the match statement
makes up the last statement in the function (frequently the only statement in
the function's immediate scope). Since the individual cases are not
terminating the function early, to get a value out of a match statement you
simply leave the last expression bare.

i.e.

    
    
        fn something... {
          match input {
          Ok(input_val) => {/* several lines of semicolon terminated code*/
                            output}
          Err(errval) => {/* several more lines of semicolon terminated code */
                  output}
        } 
    

is correct, but

    
    
        fn something... {
          match input {
          Ok(input_val) => {/* several lines of semicolon terminated code*/
                            return output;}
          Err(errval) => {/* several more lines of semicolon terminated code */
                  return output;}
        } 
    

is poor style, and

    
    
        fn something... {
          match input {
          Ok(input_val) => {/* several lines of semicolon terminated code*/
                            output;}
          Err(errval => {/* several more lines of semicolon terminated code */
                  output;}
        } 
    

is an error.

~~~
burntsushi
> So I should use `return` except when I shouldn't? This is the cognitive
> overhead problem I'm talking about.

No. Use `return` only when you _must_. If you want an early return in a
function, then you need to use `return`. If you don't need an early return,
then don't use `return` at all.

I can't remember if this was ever a cognitive load for _me_ personally. I
don't think it was.

~~~
falcolas
> I can't remember if this was ever a cognitive load for me personally. I
> don't think it was.

Well, to be fair, it sounds like you're used to semicolons having special
meaning (aside from separating expressions) from a previous language.

> As for `;`, it's just like Standard ML. `;` is for sequencing expressions. I
> love it.

It's worth remembering that most users of C, C++, Ruby, Java, Python, or
whathaveyou are not used to the semicolon having special meaning. Since Rust
appears to be primarily aimed at replacing C++, this is going to be a
significant change which will likely trip people up for awhile.

~~~
agrover
I'm a C/Python person, and it did take a question on irc for me to get my head
around how Rust does it, but now it seems so natural that it's a little
irksome to look at some of my Python code :)

~~~
steveklabnik
Ruby also does this, so if you want that natural feel in your dynamically
typed language... ;)

------
Animats
Wow. I wrote that article on LtU last night, after going over there to see
what the language theorists were saying about Rust. (And after, for the third
time in three weeks, having my Rust code fail to compile because the Rust
crowd changed the language again, after the "alpha release" and its claims of
stability: [http://blog.rust-
lang.org/2014/12/12/1.0-Timeline.html](http://blog.rust-
lang.org/2014/12/12/1.0-Timeline.html)) I wasn't expecting it to be picked up
on Hacker News.

Rust is going to be very important. The ownership system is a major step
forward in language design. It's a huge improvement over C/C++.

It's not easier to write than C++. Rust may feel clunky for people coming from
Javascript, Python, Ruby, and PHP. Having to think about lifetime issues for
mere strings is a new cognitive load. The big win with Rust is that most of
the errors are caught at compile time. This is Rust's big advantage, but alien
to scripting programmers. The Rust compiler report errors in three phases.
First you get all the syntax errors, and until the syntax is perfect, that's
all you get. Then you get all the type errors, and until the type issues are
perfect, that's all you get. Then you get the ownership errors. Ownership is a
global analysis; ownership problems involve at least two points in the
program. The compiler produces good, but very wordy error messages. (Hint to
Rust developers: put in a line length limit and word wrap for long compile
time error messages.) If your ownership design is faulty, the result is likely
to be "fighting with the borrow checker", because the problem isn't local, and
just fixing the compiler-reported error will make the problem pop up
elsewhere. The cleverness of the ownership system is impressive, but some
programmers are going to feel like they're being hammered by it. Successful
C++ programmers won't have a major problem with this. It may be tough on the
Javascript crowd.

Rust requires some advance planning, which may be incompatible with "agile"
development. It's also difficult to port code from other languages to Rust
without rethinking the ownership and bounds logic. There is a port of Doom to
Rust. It has a lot of unsafe code, because Doom's internal memory structures
are not directly compatible with Rust's. Such problems will recur as big
packages with delicate internals are ported over to Rust.

This is partly a documentation problem. The current tutorial
([http://doc.rust-lang.org/book/hello-cargo.html](http://doc.rust-
lang.org/book/hello-cargo.html)) is relentlessly upbeat and glosses over too
many of the hard problems. Once some third-party books have been written, that
situation should improve.

~~~
MichaelGG
Not easier than C++? I dunno, C++ looks like a clusterfuck of complicatedness.
I'm mostly coming from F#, with some C. Rust's ownership system _just makes
sense_ and seems to perfectly answer the questions I have when using C APIs.
Rust, for me, looks a lot like what I've wanted when writing performance F#.
I'd commit atrocities to have optional ownership in F#.

Every time I've fought with the borrow checker, it's because I've had a
serious design or conceptual flaw. (Well, apart from syntax/compiler
questions). Since you can derive most of the rules just by thinking about it,
I find it grows on you quickly. I'll be very saddened if the borrow checker
actually ends up being hurtful for adoption overall. Though I agree if you
cannot handle pointers or think about memory, Rust will be difficult. So yeah,
scripting only devs will have trouble. But! It's better than them writing the
code in C.

Rust overall seems like that. There's less random stuff and things work mostly
by thinking about safe, zero overhead abstractions, and what falls out from
those mandates. Mostly.

Now, maybe if I was a modern C++ programmer, I'd find the effort about the
same. OTOH, C++ systems don't end up as safe as Rust ones, so I'm not sure
there's a perfect comparison to be had. Maybe that'll change as C++ has
started catching up feature wise, but someone I doubt it.

~~~
sanxiyn
Overall, I think Rust is easier to use than C++ but not easier to _write_ than
C++. Writability is a specific facet of usability, which is hurt by strict
upfront checks.

Writability is a worthy thing to improve: GHC's -fdefer-type-errors feature is
a good example. I hope Rust improves its writability in the future.

~~~
agrover
I think just like other languages, writing Rust leads to a familiarity with
what the compiler wants. Then you spend more time thinking about design and
the problem at hand, and less fighting the compiler. I think Rust will
ultimately be easier than C++ to write because while there are tricky concepts
to master, there should be much fewer of them than C++ has.

~~~
sanxiyn
I disagree. While you get familiar with what the compiler wants (certainly I
did, after using Rust for more than 2 years now), it's just that Rust compiler
wants more from you than C++ compiler does.

The number of tricky concepts largely do not affect writability, because you
don't have to use them. The number of mandatory compile time checks do,
because you have to pass them.

One way to improve writability is a mode to turn off some of checks while you
are exploring. I already gave a good example from Haskell. When you are done
exploring, you can turn on all the checks.

~~~
MichaelGG
Hmm, so like a Rust flag like --allow-leaks or --corrupted-ownership?

It seems like editor support would totally dominate here. That is, realtime
checking of lifetimes and autocomplete/inline errors should be a much bigger
improvement in write times than some way to emit invalid code.

------
stebalien
I don't have an account there so I'll comment here:

> In particular, allocating a new object and returning a reference to it it
> from a function is common in C++ but difficult in Rust, because the function
> doing the allocation doesn't know the expected lifetime of what it returns.

This is what boxes are for. A Box is a unique pointer to a value on the heap
and can be used without knowing compile-time lifetimes. References and
lifetimes allow you to safely return pointers to _stack_ allocated objects. In
C++, you'd have to do this:

    
    
      MyType value;
      my_function(&value);
    

When returning references, rust uses the lifetimes instead of explicit
declarations to figure out where (on the stack) `value` needs to be allocated.

> Declarations are comparable in wordiness to C++.

Only at interfaces where the declaration also serves as documentation.
Elsewhere, types can generally be inferred.

> Rust has very powerful compile-time programming; there's a regular
> expression compiler that runs at compile time. I'm concerned that Rust is
> starting out at the cruft level it took C++ 20 years to achieve. I shudder
> to think of what things will be like once the Boost crowd discovers Rust.

Unlike C++, 1\. Macros from one crate aren't imported into another unless the
user explicitly requests that they be. 2\. Macro invocations are clearly macro
invocations. You never have to wonder if something is a function or a macro.

> The lack of exception handing in Rust forces program design into a form
> where many functions return "Result" or "Some", which are generic
> enumeration/variant record types. These must be instantiated with the actual
> return type. As a result, a rather high percentage of functions in Rust seem
> to involve generics.

How is this a problem?

> There are some rather tortured functional programming forms used to handle
> errors, such as ".and_then(lambda)". Doing N things in succession, each of
> which can generate an error, is either verbose (match statement) or obscure
> ("and_then()"). You get to pick. Or you can just use ".unwrap()", which
> extracts the value from a Some form and makes a failure fatal.

I agree that this is less than ideal. However, IMHO, this is better than Java
and C++.

Java:

Libraries tend to bubble everything. This leads to long throws clauses in
function signatures with unexpected exceptions. A user of these libraries
often catches and ignores these exceptions when writing the first draft of his
or her programs because they don't make sense (why handle IO Errors when using
a collection?). And then, because his or her program works, he or she forget
about the ignored exception cases turning them into silent errors.

On the other hand, in rust, you can only return one error. When writing a
function that has multiple failure modes, this forces the programmer to think
about the set of failures that can happen and come up with new error type.
This doesn't force the programmer to come up with a _meaningful_ error type
but it gives them the opportunity.

Additionally, like in Java, Rust programmers can ignore errors (`unwrap()`).
However, unlike in Java, these ignored errors are not silent, they are fatal.

C++:

Exceptions are unchecked and everyone I've talked to avoids them like the
plague. In the end, C++ exceptions end up acting like rust's `panic!()`
because programmers don't check them but are used like Java's exceptions
because programmers _could_ check them.

> There's a macro called "try!(e)", which, if e returns a None value, returns
> from the enclosing function via a return you can't see in the source code.
> Such hidden returns are troubling.

I agree that hidden returns can be troubling. However, in rust, only macros
can lead to hidden returns, macros use a special syntax
(`macro_name!(args...)`, and macros have to be explicitly imported.

> All lambdas are closures (this may change), and closures are not plain
> functions. They can only be passed to functions which accept suitable
> generic parameters. This is because the closure lifetime has to be decided
> at compile time.

The first sentence is correct but the last two are just wrong:

    
    
        fn takes_a_function(f: Box<Fn()>) {
            (f)();
        }
        fn main() {
            takes_a_function(Box::new(move || { println!("hello world") }));
        }
    

The `Box` allocates the closure on the heap and the `move` causes the closure
to capture by value. This means that this closure (`f`) can be moved freely
without lifetime restrictions because it doesn't reference the stack. However,
most functions that accept closures use generics and do any necessary boxing
internally to make the user's life easier.

> Rust has to do a lot of things in somewhat painful ways because the
> underlying memory model is quite simple. This is one of those things which
> will confuse programmers coming from garbage-collected languages. Rust will
> catch their errors, and the compiler diagnostics are quite good. Rust may
> exceed the pain threshold of some programmers, though.

Rust is a _systems_ language. It exposes a lower-level (not simple) memory
model because systems programmers need it. If you want garbage collection, you
are free to roll your own (yes, you can actually do this in rust).

> Despite the claims in the Rust pre-alpha announcement of language definition
> stability, the language changes enough every week or so to break existing
> programs.

Re-read those claims. Alpha means fewer breaking changes and no "major"
breaking changes not stability.

~~~
falcolas
> References and lifetimes allow you to safely return pointers to stack
> allocated objects.

This is explicitly called out as non-idiomatic behavior in the documentation,
however. The preferred action is to allocate on the caller's heap and pass a
mutable reference down to the callee.

In fact, in general it's recommended not to use Box, because it complicates
human reasoning about the code. And while it gets around a lot of the
compiler's restrictions, its akin to writing <language of choice> in Rust,
which is frowned upon in any language. Recommending its use so broadly is
doing a disservice to people who want to learn Rust.

> Only at interfaces where the declaration also serves as documentation.
> Elsewhere, types can generally be inferred.

Except where they can't, and those locations aren't terribly consistent. The
Rust designers have publicly announced their preference for explicitness over
inference, and the language reflects that.

> On the other hand, in rust, you can only return one error.

This is not unique to rust, or any language really. You can only throw one
exception at a time. You can only set one errno at a time. You can only return
one `error` at a time.

> macros have to be explicitly imported

Except for the built in ones, which are the only ones referenced by the OP.
Also, by placing the macro delimiter `!` between the name and the parenthesis,
it makes the macro harder to scan for visually. I imagine that any editor will
want to set up special rules to highlight these distinctly, and having special
highlighting for the ones known to change the program flow would be
beneficial.

> It exposes a lower-level (not simple) memory model because systems
> programmers need it.

Low level memory _is_ simple: write to, read from, write to referenced, read
from referenced. The OS adds one more major operation: get heap memory.
Everything else is added by languages or libraries.

That said, Rust's restrictions on memory lifetimes results in more simplistic
memory related code. When you have to jump through extra hoops to create a
pointer which may be used beyond a single scope, and the compiler creates so
much friction when you want to do anything with them in that greater scope,
people will defer back to simplistic memory code.

I'm not certain if this is good or bad; it just is at this point.

> Alpha means fewer breaking changes and no "major" breaking changes not
> stability.

Any breaking changes affect stability, affects documentation (Rust's library
documentation is behind the actual code as of a week ago), and affect 3rd
party libraries. The results of this is that if you're not Mozilla, there are
significant barriers to writing Rust code right now, and I would not
personally recommend learning or writing Rust right now to anybody.

~~~
pcwalton
> Except where they can't, and those locations aren't terribly consistent.

Why aren't they consistent? The Rust type inference is generally very good,
and the places where you have to annotate are places where any typechecker
would force you to annotate, because the types are simply underconstrained
(e.g. the return type of Vec::collect or mem::transmute).

> The Rust designers have publicly announced their preference for explicitness
> over inference, and the language reflects that.

As the original author of the typechecker, I can state that the idea that we
intentionally made the type inference less powerful than it could have been is
totally false. It's always been as powerful as we could make it, except for
interface boundaries (where type annotation is needed because of separate
compilation anyway).

~~~
falcolas
> Why aren't they consistent?

So, I went back to do a bit of research, and it's gotten better since this
first bothered me, my apologies. My beef was with the `let x =
vet::Vector::New::<i32>()` vs `let x: Vec<i32> = vec::Vec::New()`. Perhaps not
the best way to word it, so consider this objection retracted. :)

> the idea that we intentionally made the type inference less powerful than it
> could have been is totally false

Except for function definitions, where the types could be inferred from the
function bodies, but are not:

[https://www.reddit.com/r/rust/comments/2bcof3/rust_type_infe...](https://www.reddit.com/r/rust/comments/2bcof3/rust_type_inference_question_functions_vs_closures/)

Plus (and this is more related to the complete lack of implicit type
conversions), there are types everywhere in the program. I frequently can't
write a number without having to append a type, even when the type has been
explicitly defined previously.

Here's one of my favorites from a recent attempt to write a ray tracer:

    
    
        let mut s: Vec3<f64> = Vec3{x: 0f64, y: 0f64, z: 0f64, w: 0f64};

~~~
drbawb
The default types for bare literals is described in RFC #212
([https://github.com/rust-lang/rfcs/pull/212](https://github.com/rust-
lang/rfcs/pull/212))

To summarize: bare FP literals default to f64, bare integral literals default
to isize. (NOTE: isize is recently renamed from int. It is a pointer-sized
integer.)

(EDIT: The default for integer literals may be superseded by a later RFC. I
seem to recall that the default is actually i32 now, but I can't find a PR to
back up that claim.)

So you could easily get a Vec3<f64> like so:

    
    
        let mut s = Vec3 { x: 0.0,  y: 0.0, z: 0.0, w: 0.0 };
        let mut t = Vec3 { x: 0f64, y: 0.0, z: 0.0, w: 0.0 };
    

The key here is that integral literals and floating point literals are
distinct.

A bare literal of the form `0` is an unconstrained integral literal.

Whereas a literal of the form `0.0` or `.0` is an unconstrained float literal.

In practice it is very rare for me to annotate my numeric literals. If the
variable escapes the stack frame it will be constrained by the signature of
the function anyways. If not I constrain the type inline (`let x: T = ...`)
and use the appropriate bare literals.

~~~
steveklabnik
You are right that this changed, but I can't find it in the RFCs either.
[https://github.com/rust-lang/rust/pull/20189](https://github.com/rust-
lang/rust/pull/20189) implemented it. And it is what everyone agreed upon....
hmm

~~~
steveklabnik
Found it! [https://github.com/rust-
lang/rfcs/pull/452](https://github.com/rust-lang/rfcs/pull/452)

------
alkonaut
> In particular, allocating a new object and returning a reference to it it
> from a function is common in C++ but difficult in Rust, because the function
> doing the allocation doesn't know the expected lifetime of what it returns.

I'd like to see a code snippet explaining this problem.

~~~
kam
Yeah, it's unclear what he's talking about there. Normally when a function
allocates a new object, it would want to return it by move (transferring
ownership), rather than by reference. That doesn't involve any lifetimes.

    
    
        fn make_a_foo() -> Box<Foo> {
            Box::new(Foo { a: 5 })
        }
    

If the function allocated memory and only returned a borrowed reference, who
would be responsible for freeing it? Yes, Rust will make you stop and think
there, as it enforces memory safety.

In cases where it does make sense to return a reference to a new object, like
allocating from an arena, the lifetime ('a) of the returned reference will be
the same as the lifetime of the arena.

    
    
        fn new_from_arena<'a>(arena: &'a TypedArena<Foo>) -> &'a mut Foo {
            arena.alloc(Foo { a: 5 })
        }
    

But Rust can infer the lifetime, so that can be shortened to:

    
    
        fn new_from_arena(arena: &TypedArena<Foo>) -> &mut Foo {
            arena.alloc(Foo { a: 5 })
        }

~~~
anon4
Any reason you would ever want to return a Box instead of just a Foo, which
the caller can then put in a Box if so desired?

~~~
kibwen
I can think of a case: when you want to return a type whose size is not known
at runtime (a "dynamically-sized type" a.k.a. DST), then you need to stuff it
behind something else whose size is known so that the compiler can statically
determine how much memory to allocate before calling your function. You could
use a reference for this task, but only if, as per Rust's usual rules, you
have a parameter to your function whose lifetime you can tie it to. If you
don't have such a parameter, then a Box is your next best bet.

Somewhat related to this, there's also currently a language deficiency where
you can be forced to use Box when returning a closure from a function. This
will be addressed shortly after 1.0.

------
Q6T46nT668w6i3m
> Despite all this, Rust is going to be a very important language, because it
> solves the three big problems of C/C++ that causes crashes and buffer
> overflows. The three big problems in C/C++ memory management are "How big is
> it?", "Who owns and deletes it?", and "Who locks it?". C/C++ deals with none
> of those problems effectively. Rust deals with all of them, without
> introducing garbage collection or extensive run-time processing. This is a
> significant advance.

What? C++11/14 solves these issues.

~~~
pcwalton
> What? C++11/14 solves these issues.

You're right that C++ provides a solution to the first two, but C++ locking
via std::mutex isn't done in the same way as Rust: in Rust the mutex owns the
data and prevents you from getting access to it unless you lock. std::mutex,
however, is a separate value from the data it protects and it's up to you to
coordinate access to that data.

I would also argue that Rust is a _better_ solution to the first two issues.
Modern C++ does not solve the problem of use-after-free (dangling references
and invalid iterators are very possible, and common in large codebases). This
is something that I don't believe C++ _can_ solve without becoming a radically
different language. Furthermore, Rust forces you to use the right patterns
unless you type "unsafe": this is, again, important for security, reliability,
and developer productivity, reducing the amount of time you spend in the
debugger.

~~~
zanny
My simplification of matters is that while C++ _can_ now do everything right,
it still easily lets you do everything wrong.

Rust compels correctness, so for any project where you can't trust your
coworkers aptitude towards correctness (and that is to say you even trust your
own) Rust is an insane productivity booster. We could have avoided millions of
hours of work and thousands of zero day and system destroying bugs if we had
OS cores written in a language like Rust.

~~~
ssalazar
> so for any project where you can't trust your coworkers aptitude towards
> correctness

So, for _any_ non-trivial project. People _will_ make mistakes, no matter how
skilled or experienced they are. Catching these mistakes at compile-time can
be a huge gain for security and stability.

Though it remains to be seen is what kind of maintenance/development burden
these constraints introduce over the longer term lifecycle of a software
project.

------
hurin
I tried to learn a bit of rust and I couldn't shake the feeling that rust is a
very ugly language, like uglier than c ugly.

~~~
jml7c5
What makes you say this? And what is your prior language experience?

~~~
Animats
_I tried to learn a bit of rust and I couldn 't shake the feeling that rust is
a very ugly language, like uglier than c ugly._

 _What makes you say this? And what is your prior language experience?_

Right there is the problem. There are many programmers for whom it's their day
job. Others depend on their code doing something useful and important. But
they're not theoreticians, don't have advanced degrees in CS, and haven't
written in a dozen languages. A new language has to be usable by them to get
traction.

The Rust community, at this point, is mostly people who know several
programming languages and want to try a new one. Look at the comments above
from people who compare type systems in different languages and are aware of
the strengths and weaknesses of different approaches. Note the references to
obscure languages and research papers most programmers have never heard of,
let alone used or read. This is not the target market for a new language, if
it is to be a success. It has to be used by people who don't debate language
theory issues while the Super Bowl is on.

------
twic
> I just hope the Rust crowd doesn't screw up.

If i had a pound for every time i'd heard this sentiment, i'd be a rich man!

