Pretty much all of the ergonomics improvements this year have been improving on things you can't do in C to begin with. Like automatic serialization (serde). Or const generics. Or error handling via ?. Or pretty much any reasonable string manipulation ever.
There's a legitimate debate to be had with the ergonomics of C++ vs. Rust (though I think Rust wins there too). But not with C. C, as a language that makes you jump through hoops to even get a hash table, doesn't even come close.
It's almost like Chuck Moore coming on HN and saying he finds Forth to be the most productive language. Of course it is, for you. (Nothing against the productivity of Forth or Rust.)
Rust is quite amazing, though. Very slick, to the point where I use it and I don't care that much about things running fast or with low memory requirements, I just want something with the syntax and comprehensibility of python/ruby/etc (at least compared to erlang/elixir, which I'd otherwise use -- not having local mutable variables makes things a bit more puzzling for no reason like three times a day) and the sweet tools from haskell, and Rust fits the bill.
The compiler will catch many errors that other languages consider logic errors; if your source code compiles, it tends to run as expected.
As for the disclosure: I'm a normal software programmer, and haven't written a single line of code for rust's compiler and tooling.
I think c++ without inheritance would be a very nice language.
But single inheritance, used judiciously, has really led to some vastly better designs in my experience and doing away with inheritance would generally mean those designs would just be redone with a clumsy "let's fake up inheritance" interface.
I think you can write bad code in any language. Bad C++ is especially egregious, as it's possible to make the bad code practically incomprehensible even at a surface level. However, I suspect that carving feature after feature away from C++ leaves a language that is now just as good for writing toy programs ("hey, look how elegant the language is now that pesky inheritance/template/exception/<insert hated feature of choice> is gone"), but will now allow you write verbose and shitty (but shallowly more understandable) code in place of the C++.
I do find the sheer size of C++ objectionable (the usual arguments about how nearly all C++ programmers seem to program in subset "house styles" of the language). I am generally very suspicious of efforts to replace C++ that come from people who don't seem to understand it at all, however. Generally I like Rust in this regard as the Rust approach seems to display a mature understanding of what was actually good about C++ (constrast: Go).
With all these years the amount of UB, memory corruption issues and security exploits only got bigger.
We need a major IoT meltdown to get rid of it, unfortunately it won't happen until the industry lets UNIX clones go.
Rust isn't going to stop IoT makers from leaving ports open and default passwords set.
Bad defaults is a problem with IoT devices, but far from the only problem.
You don't even need Rust, Algol 68 would be enough.
Redox is a Unix-like system.
UNIX is married with C by design, just how browsers are with JavaScript.
Actually you are right in one thing, if Redox offers POSIX support then it needs to sandbox them.
There is a big difference in having POSIX support and being a UNIX.
Windows, IBM i, IBM z/OS, Unysis MCA ClearPath, Green Hills INTEGRITY OS, Genode and many other OSes have POSIX support, yet their architectures have nothing to do with UNIX.
This can be solved with a templating system, not a new language.
For my first large project in Rust, I ran into several issues where the type system was complaining that I couldn't take the references of certain variables in certain ways. Most of the time, it was clear to me (eventually) that what I wanted to do was actually unsafe. It takes some time, but a lot of the pain involved with starting out with Rust is realizing that the patterns you've been using all along in C/C++ were fundamentally unsafe from the beginning.
The rest of the time, though, what I wanted to do was safe, but I couldn't figure out how to structure the code to get Rust in a position where it could guarantee that safety.
Perhaps what we really need for the engineering that really calls for this class of product (a systems language), is not more ergonomics, but an acceptance that some small sacrifice in ergonomics and possibly productivity is a small price to pay to make some real headway in the problem of actually providing correct software? Cutting of entire classes of errors and subsequent exploits is an enormous gain for such a small price.
Put another way, every bug you allow through that could have been found with more diligence is really you offloading development time, effort or cost onto your users. That's not to say unlimited time should be spent during development to find bugs, but there is a trade-off happening, and I would hazard that most developers spend less time than they should. In these terms, I think Rust is an amazingly productive language regardless of whether it seems harder to use and makes you feel somewhat less productive.
Which ergonomic issues are your main concerns?
Some things I can think of
- Libraries focusing on optimal performance over ergonomics
- Lifetimes
- Results not being quite as ergonomic as exceptions
While it has rough spots now, I'm hopeful for the future.
The impression I've had watching Rust's evolution is they want to push the language to its limits, find the weak points, find ways of fixing it, and repeat. They don't want to speculatively throw in features. For example, we started off with try!() and later got .?.
Improving the documentation would also improve people's perceptions. I've gone through waves of feeling like Rust's error handling is close enough to the ergonomics of exceptions. When I had surface knowledge, it seemed great. I then started using it and running into problems. I then came across random blog posts and it became easy again.
For a further discussion on documentation, see https://www.reddit.com/r/rust/comments/67fb8e/rust_tribal_kn...
The next step is creating ergonomic libraries. ezstring is an example of people experimenting with this.
It's sort of like SVN vs git. When you start you might wonder how can anybody manage to commit a line of code with it, but once you know it, you can't believe you've lived without rebase.
I've been programming in C for 17 years, and in Rust for 2 now. In the first year I had to get help from StackOverflow or IRC for every function I wrote. Now I'm past that, and I'm much much more productive in Rust. I have full control of memory, but no `free()` to write! Strings are easy! Dependencies are easy! I can iterate over BTreeMap with 1 line of code (which inlines to code as efficient as I'd write manually).
It's great, once you know it.
Tit for tat. When you gain particular categories of guaranteed correctness there are things you needn't worry about, and that saves you lots of trouble down the road.
How much ergonomical pains such a gain is worth is obviously debatable, but I think it's absolutely reasonable to say that trading guaranteed correctness for comfort more often than not is going to be the right thing to do in systems-level programming. And the lower-level you go, more so.
What I mean is, it's not the closures exactly that are the problem. It's just that closures are one of the times it would be really really convenient if you could have multiple mutable references to something. You end up having to use `Rc<RefCell<>>` as described here:
http://gtk-rs.org/tuto/closures#using-non-gtk-rs-object-into...
This is also mentioned in the Tock PDF: https://sing.stanford.edu/site/publications/levy-plos15-tock... in section 3.2. I'm not really sure how they overcame that in Tock. I guess using RefCell?
Anyway it all seems very awkward.
There are certainly some things that should just be obvious now, though. Using the C++ namespace separator of :: is just ludicrously obtuse for an extremely common symbol, using the & for refs is archaic (I mean... you could have just called it a ref. ref T instead of &T. And then just ref(foo) or foo.ref to get a ref to foo.) And the syntax for lifetimes is horrible, with the 'a and the fact that in practice its about as significant as naming parameters in a C++ function definition in a header (ie, pointless - the words are discarded by the compiler every time).
And I certainly would have argued for whitespace significance, at least as an option, instead of classic semicolon spam.
Given all that, Rust is still, IMO, the best programming language we have right now for native performance, period. We can criticize what we don't like but we should at least agree its the best we have.
Obtuse? It's sort of common. Multiple languages use it. Personally I like the namespace separator being distinct from the object/struct element accessor. At least they didn't copy PHP in using backspace...
> using the & for refs is archaic (I mean... you could have just called it a ref. ref T instead of &T. And then just ref(foo) or foo.ref to get a ref to foo.)
Please, let's not have more cases where things look like functions but aren't. Functions should look like functions. Operators should look like operators. You might have to learn a small set of operators for a new language. This is front-loading some confusion and learning pain for ease of use later. It may make the language harder to read for people that don't know the language, but anyone reading the source code with the aim to make some changes should probably know the operators at least. I'm not sure giving it a slightly more expressive name but making it look like something else actually makes life easier for those people.
> And I certainly would have argued for whitespace significance, at least as an option, instead of classic semicolon spam.
Optional whitespace significance? That sounds like a recipe for disaster, IMO. I can see a case for one or the other, but mixing of modes like that when it deals with something that is by nature somewhat invisible (or meta), seems prone to problems.
Also, examining why Python has had problems with functional style workhorses like map might shed some light on the negative aspects of whitespace dependent syntax.
Of all the glyphs used in the language, :: is probably in the top 5 for frequency of use (probably higher than even * in Rust, considering the infrequency of pointer usage and that multiplication isn't that common an operation in general code) but uses two glyphs instead of one.
It would have required different design constraints starting out to figure which glyph would be best suited instead of ::, but :: is still really ugly in all the languages that use it when its such a common symbol. I wouldn't argue overloading . is right, but I'm having a hard time seeing why a single colon doesn't work - foo:bar:baz. Maybe the parser finds scoping and explicit type names on definitions (ie let foo: i64 or in function definitions) require too many passes to distinguish?
`&` isn't a parameter annotation in Rust, it's two unary operators, two type annotations (general) and a pattern-matching operator.
The latter of which `ref` also is, incidentally, it means "capture a value by reference" in a pattern: https://play.rust-lang.org/?gist=30b436d83701f74b986aea978fa... (& meaning "capture a reference by its target" in that context, which is logically the structural inverse of the operator)
use .\greetings\hello;
use ..\foo;
use \bar;
right now these are: use self::greetings::hello;
use super::foo;
use ::bar;
I think the PHP way would have been way betterWhat is wrong with ::? It's visually distinct, isn't easily confused for other things, and unused for anything else, which pretty much hits all the criteria I care about for this feature.
I'm seriously asking, why do people dislike ::? Is there an actual basis, or do people just not like the look?
Also, because of how the metaphor for paths is broken, the relative paths in Rust are not intuitive. That's why you HAVE TO put `self::foo` because the default is not the same as what you'd expect if it were a path.
It's overly complicated compared to just letting you use actual Windows paths.
because how do you parse
let x = a/foo();
is that a::foo() or a / foo()?If you use \ it's unambiguous, a\foo() corresponds to a::foo() while a/foo() is division
So, why again is :: such a bad choice, given all this?
Even for windows paths, backslash has caused a lot of problems in various tools[1][2][3]. Just google "backslash path error" for many pages of problems. Even early DOS developers weren't happy with the need for backslash, and made regular slashes work in paths. That doesn't work everywhere in Windows, but it works in a lot of places. Following Microsoft's mistake because of an accident of history (they has already used forward slash for command flags before implementing path hierarchies so needed a different character) and dealing with the same problems they have is not a point in backslash's favor.
> :: is two characters and is only familiar for C++ programmers
It's familiar for whoever learns it for the language they are learning. That it does not necessarily have an association with concepts from other languages or systems that don't apply cleanly (such as the namespace corresponding to the path, which may not be true) is a positive.
1: https://pythonconquerstheuniverse.wordpress.com/2008/06/04/g...
2: https://github.com/rstudio/shiny/issues/1009
3: http://www-01.ibm.com/support/docview.wss?uid=swg21635233
use foo::bar;
doesn't actually use a relative "path" from the current moduleyou need to use
use self::foo::bar;
I think this is a confusing default, and it would have never ended up this way if Rust used Windows-path-looking namespace syntaxif you're writing a parser and manipulating actual arrays of bytes, you don't have an issue with backslash, it's just another character to you
Ugh, no. There are references all over the place when I write Rust code -- it would be a serious bummer for me if annotating those types and making those references took up 4 characters for "ref " instead of just the 1 for &.
let foo:'static str = "foo";
Whenever I see an apostrophe, my mind defaults to frantically searching for its counterpart at the end of the string they're enclosing. Just like for parentheses; imagine how confusing it would be if ' would have been ( instead. let foo:(static str = "foo";For what it's worth, there are many cases even in the natural language where ' is not supposed to have a "closing" counterpart - indeed, the "it's" in this very sentence is one such example. Then you have the use of ' to denote feet and minutes of arc. Now, technically these are all actually different symbols, with their own Unicode codepoints etc - but in practice, people use ' for all of them, and it doesn't seem to be confusing anyone. You could treat the ' in Rust as something along these lines.
In fairness, you should never be searching for matching apostrophe. Single quote, maybe. The fact that it's an apostrophe should also trigger that it might have something to do with possession... (or that something was omitted).
That have chosen safety first and appear to be working on ergonomics without sacrificing that.
Well, there you go. It's an alternative to C. Those tend to get messy (see also, C++).