
Things Rust shipped without - AndrewDucker
http://graydon2.dreamwidth.org/218040.html
======
IvyMike
> goto (not even as a reserved word)

I haven't done this for a while, but once upon a graduate program I wrote a
compiler from a made-up-language (MUP) to C. MUP had some strange control
structures, and if C did not have "goto", it would have been a lot more
difficult to implement those structures. Since then, I have always thought
languages should have a "goto" statement that human-written code is not
allowed to use. :)

~~~
chjj
I've always defended goto and gotten a lot of flak for it. As soon as I say,
"I wish I had X-language had gotos", I see jaws drop. Response: "Wow, haven't
you heard the news?! GOTOs are considered harmful!"

I think goto should be in almost every language. It's one of the most
primitive instructions, why shouldn't it be available when needed? Yes, it can
be misused, _just like any other feature in the language_ , but it can also be
used to great benefit. State machines, for example, can make good use of
gotos.

Hell, look at any unix library your machine uses every day. The ones you don't
even think about. Start with libncurses: I promise there's a few gotos where
needed.

    
    
        $ find ~/ncurses-5.9 -name '*.c' -print0 | xargs -0 grep goto | wc -l
        70
    

Raise your hand if you plan to stop using ncurses because of how opposed to
how "harmful" goto statements are.

Oh, here's tmux, if you're interested (one of the most beautifully written C
programs):
[https://github.com/tmux/tmux/search?utf8=%E2%9C%93&q=goto](https://github.com/tmux/tmux/search?utf8=%E2%9C%93&q=goto)

~~~
istvan__
I do not use goto in my code. What do I do wrong? :) Ok, I have to admit that
I used it on C64 in the 80s.

Anyways, exceptions are sort of gotos or at least they can behave that way.

~~~
sklogic
If you're not implementing fast FSMs, fast bytecode interpreters (and dynamic
dispatchers in general), and you're not using metaprogrming to the full power,
not implementing multiple embedded DSLs - then you can live without a goto.
Otherwise it is essential.

~~~
pjmlp
Metaprogramming to the full power sounds like Lisp. It doesn't have goto.

~~~
sklogic
> Metaprogramming to the full power sounds like Lisp.

It does, yes, although many Lisps got a pretty limited backend for this sort
of things. My preferred metaprogramming environment must have a fallthrough
mode for allowing generating low-level code where Lisp semantics is not
sufficient. Rust seems like a very good target platform in this sense, so the
lack of goto really hurts.

> It doesn't have goto.

Of course they do (tagbody in Common Lisp, for example). And when they don't,
it's often relatively easy to add one.

~~~
pjmlp
> Of course they do (tagbody in Common Lisp, for example). And when they
> don't, it's often relatively easy to add one.

I was wrong, however it is much more limited than the goto everywhere from C,
as where the labels are located is clearly defined in the tagbody and not in
every possible statement.

------
andrepd
What about things that Rust shipped without that _should_ have been included?

~~~
nwmcsween
An effects system.

A safe stdlib - aborting on malloc failure is not safe.

~~~
gnuvince
I'd need to recheck my vocab, but I'm pretty sure aborting is always safe.

~~~
ajb
Not if you want to write an OS.

~~~
rcxdude
Then you won't use the stdlib anyway.

------
DannyBee
" Next time you're in a conversation about language design and someone sighs,
shakes their head and tells you that sad legacy design choices are just the
burden of the past and we're helpless to avoid repeating them, try to remember
that this is not so."

I think rust is neat, but this is somewhat arrogant.

Rust is _amazingly young_. 10-20 years from now, when rust hopefully has
bajillions of users, if this is still true, _then_ you can say it. I mean, do
you really believe that Rust won't have things that turn out to be warts from
1.0 it can't remove 10-20 years from now?

~~~
hyperpape
I think you're misreading this. I read it as saying that these things are sad
design choices in many similar languages, but that Rust has avoided them.
Nothing follows about them not having included other sad design choices that
they're unaware of.

The point is that you can at least try to avoid the things you view as sad
design choices--you're not necessarily stuck with them.

------
kazinator
I used Common Lisp's goto (tagbody with go) to implement portable tail
recursion: a "tlet" construct that looks like the "labels" syntax for defining
a local function, but is just a stackless goto thunk with parameters.

[http://www.kylheku.com/cgit/lisp-snippets/tree/tail-
recursio...](http://www.kylheku.com/cgit/lisp-snippets/tree/tail-
recursion.lisp)

This also provides some facilities for doing cross-module tail recursion among
top-level functions. Here, continuation to the next function is provided by
wrapping the function call in a closure, performing a non-local exit which
abandons stack frames up to a dispatch loop, which then invokes the closure.

------
andresmanz
I'd like Rust to be shipped without counterintuitive standard library function
names and that book with all its style 'recommendations'. And I'd like the
Rust compiler to be shipped without that non-snake case warning enabled by
default.

Language creators won't endear themselves to me by ranting. The problem I have
with Rust is _not_ the language itself.

~~~
pcwalton
This is the first I've heard complaints that Rust is too strict with
formatting. If anything, the popularity of gofmt (which is far more
opinionated than rustc's default warnings are!) is a testament to the fact
that people want languages to be ruthlessly opinionated regarding style these
days.

~~~
andresmanz
That's absolutely OK and I do understand that people want that. I actually
like snake case and only slightly prefer camel case. I'd write snake case in
large open source projects, if it's actually preferred. But it's very awful to
type snake case code on my keyboard and I'm not ready yet to switch to a US
keyboard. The worst thing about that warning is that I get some kind of a bad
conscience by disabling it.

~~~
nightpool
have you thought about binding underscores to some other key combination at
the operating system level?

~~~
cpeterso
SHIFT+SPACE could be a good keyboard shortcut for underscore because
snake_case's underscores represent spaces between words.

~~~
nightpool
Oooh, I hadn't thought about this. I might want to try this even on my (US)
keyboard!

------
shawn-butler
I would add Ropes: [https://github.com/rust-
lang/rfcs/issues/653](https://github.com/rust-lang/rfcs/issues/653)

Given the frequency of manipulating large bodies of text in contemporary
programming I do not agree it is best left to a library implementation.

Without ropes as core std average rust developers will do what they did in
java, c++, objC and simply use and abuse std::strings in all cases including
those where it will perform poorly.

[https://en.wikipedia.org/wiki/Rope_(data_structure)](https://en.wikipedia.org/wiki/Rope_\(data_structure\))

[pdf]
[http://www.cs.rit.edu/usr/local/pub/jeh/courses/QUARTERS/FP/...](http://www.cs.rit.edu/usr/local/pub/jeh/courses/QUARTERS/FP/Labs/CedarRope/rope-
paper.pdf)

~~~
ewillbefull
I think some progress will be seen in libraries first, namely things like
tendril.

[https://github.com/servo/tendril](https://github.com/servo/tendril)

------
ajkjk
What does "unions that allow access to the wrong field" mean?

~~~
pcwalton

        union foo {
             int x;
             float y;
        };
    
        union foo bad;
        bad.x = 100;
        printf("%f\n", bad.y); // undefined behavior (though usually works)

~~~
SomeCallMeTim
Which is actually a _useful_ feature in some obscure optimizations, like this
fast (approximate) square root:

    
    
    		float half_r=r*0.5F;
    
    		union
    		{
    			float y;
    			int32_t i;
    		};
    
    		y=r;
    		i=0x5f375a86-(i>>1);
    		y=y*(1.5F-(half_r*y*y));
    		return y;

~~~
Scaevolus
That hasn't been an optimization for 15 years now. Fast approximate inverse
square root is a builtin operation on most FPUs-- on x86, it's RSQRTSS, which
tends to be the same cost as a floating point multiply. (for Haswell, it has a
5 cycle latency, and 1 cycle reciprocal throughput)

~~~
SomeCallMeTim
Interesting, though not useful unless there's a good way to access it from
portable C/C++. An __asm__ section or equivalent would work, but would only be
useful on a particular CPU -- and different compilers use different syntax for
embedding assembly, so that's not ideal either.

But where I'd more likely use that optimization at this point is on Arm or
ATmega processors. ARM doesn't seem to have an approximate inverse square
root, based on a quick check, and ATmega are frequently still stuck with
software floating point, so I'd hardly say that the optimization is dead.

------
MrBuddyCasino
I don't get why those are bad?

\- random-access strings

\- auto-increment operators

~~~
steveklabnik
The first is bad because of UTF-8, basically. It's unclear what an index
should even return: bytes, codepoints, grapheme clusters? Furthermore, because
it's a variable-length encoding, it's not O(1) access, which is what []
implies, and since Rust tries to surface the cost of operations, it would be
inappropriate for Rust.

(Note that Rust _does_ have a ranged syntax here, which returns bytes, and is
O(1))

Pre vs post increment just leads to a lot of confusion, and doesn't give you
much over `x += 1`, in my opinion. Not sure what Graydon's reasoning is here.

~~~
comex
Just as additional context, since this seems to come up a lot - that does not
mean that UTF-8 is bad. The main alternative is UTF-32, which provides random
access to codepoints rather than bytes, but since Unicode graphemes consist of
multiple codepoints, UTF-32 is effectively a variable width encoding as well
for most purposes, just one that uses much more memory than UTF-8 most of the
time and never uses less.

~~~
steveklabnik
Oh yeah, I don't think any of this makes UTF-8 bad, in fact, I think it's the
best choice.

It just reveals the inherent complexity in handling string data.

------
15155
How about stdlib-blessed async IO? Or even async/await keywords (simple CPS
transformation) a la C#?

~~~
steveklabnik
Well, it did, but these are things that are good _not_ to have, not things
that would be nice to have.

If those are things you do want to have, well, we didn't have a design for AIO
that we were happy yet, as even the most advanced Rust library, mio, is still
a work in progress. [https://github.com/rust-
lang/rfcs/issues/1081](https://github.com/rust-lang/rfcs/issues/1081)

As for async/await, [https://github.com/rust-
lang/rfcs/issues/388](https://github.com/rust-lang/rfcs/issues/388)

------
saboot
Rust also shipped without reflection, which was available in the beginning. I
was a bit disappointed as it was something I would have made use of for
serialization.

~~~
FrozenCow
Wouldn't it be better to create serialization functionality at compile-time?

In the Java space some libraries are moving to compile-time code generation
instead of relying on reflection. It is a huge win, since a lot more can be
checked beforehand. Dagger 2 is a good example how it can be beneficial. It
provides dependency injection at compile-time, which will in turn check
whether all dependencies are satisfied. I haven't seen this being done at
compile-time before, but it is definitely a step up from reflection-based DI.

I'm not sure whether macros of Rust can provide such functionality, but the
developers seem conservative when it comes to adding functionality. That seems
like a good thing.

~~~
saboot
I was referencing at compile time, yes. How does Dagger generate the code?
Does it run an executable first?

Yes, in C++ there is a similar library called ROOT which generates c++ files
called "dictionaries" storing class information by running an executable over
the files. I don't see (or understand) the downsides in providing the
functionality for performing those steps at compile time though. The
developers of ROOT are currently pushing for it to be included in C++17 (or
beyond).

------
alfiedotwtf
Perfection is achieved, not when there is nothing more to add, but when there
is nothing left to take away. \-- Antoine de Saint Exupéry

------
merlincorey
How does one accomplish loop-unrolling as in Duff's Device in rust, if case
statements do not fall through?

~~~
steveklabnik
Well, you generally don't, because Duff's Device isn't generally regarded as a
good idea anymore, in my understanding:

    
    
      > It turns out that with branch predictions and the relative speed of CPU
      > vs. memory changing over the past decade, loop unrolling is pretty much
      > pointless.
    

[http://lkml.iu.edu/hypermail/linux/kernel/0008.2/0171.html](http://lkml.iu.edu/hypermail/linux/kernel/0008.2/0171.html)

~~~
veddan
Still, there are cases where fall-through can be useful:

    
    
        int remaining = length % 4;
        switch (remaining) {
            case 3: h ^= (data[(length & ~3) + 2] & 0xff) << 16;
            case 2: h ^= (data[(length & ~3) + 1] & 0xff) << 8;
            case 1: h ^= (data[length & ~3] & 0xff);
                    h *= m;
        }

~~~
steveklabnik
[https://github.com/pythonesque/fallthrough](https://github.com/pythonesque/fallthrough)
can emulate the fallthrough style if you really, really want to have it. It
seems like it hasn't been updated in a while, though.

~~~
Jweb_Guru
In the post-1.0 world, a repository not having been updated for a few months
doesn't automatically mean it no longer works :P

~~~
steveklabnik
That's true but January 11 is in that weird grey area...

~~~
Jweb_Guru
Let me be clearer: that repository works fine and doesn't rely on the standard
library at all.

------
sklogic
Lack of `goto` is a _huge_ disadvantage for a language with macros. Pity they
did not want to provide something like `unsafe` keyword which would enable all
the dirty, dangerous, high-performance stuff.

~~~
frivoal
One of the things Servo (the web browser engine written in Rust) has not
decided to write from scratch is a (high performance) js engine. If they did,
they might have more feedback on this kind of things.

------
yurish
What is wrong with UTF-16 support?

~~~
Skalman
It's an encoding that isn't good at anything: it's neither ASCII-compatible
(like UTF-8), nor fixed-length (like UTF-32), but because most characters
require only 2 bytes, developers frequently assume that none require more,
leading to bugs when a character eventually is represented by 4 bytes.

~~~
yurish
I don't know much about Rust and Rust library, so I have a question: what if I
what to develop Windows only software in Rust, will I need to convert back and
forth between UTF-16 and UTF-8 (or whatever Rust uses in other parts of the
library)?

~~~
tatterdemalion
Yes.

The Rust std library had to pick a string encoding, and it picked UTF-8 (which
is really the best Unicode encoding). The String type is platform neutral and
always UTF-8.

However, it does provide an OsString type, which on windows is UTF-16. Maybe
there is a library - and if not, one could be written - targeting Windows
only, and implementing stronger UTF-16 string processing on the OsString type.

EDIT: To be clear, Rust's trait system makes this very easy to do. You just
define all the methods you want OsString to have in a trait WindowsString, and
implement it for OsString, even though OsString is a std library type. One of
the great things about Rust is that its trivial to use the std library as
shared "pivot" which various third party libraries extend according to your
use case.

~~~
Manishearth
I believe Rust uses WTF-8 as an intermediate format for windowsy things
(cheaper), but I'm not sure.

~~~
the_why_of_y
What is... oh... UTF-16, the gift that keeps on giving... this is, at the same
time, utterly hilarious and horribly depressing:

[https://simonsapin.github.io/wtf-8/](https://simonsapin.github.io/wtf-8/)

But there is actually prior art here - Java's contribution to perverse Unicode
encodings is called "Modified UTF-8" and encodes every UTF-16 surrogate code
unit separately.

[http://docs.oracle.com/javase/6/docs/api/java/io/DataInput.h...](http://docs.oracle.com/javase/6/docs/api/java/io/DataInput.html#modified-
utf-8)

------
jlarocco
I'm sorry, but I have a hard time being impressed by any of those. They're all
just fixing things that were busted in C.

I mean good for Rust, but C is a pretty low bar. Does any language created in
the last 20 years make those same mistakes?

~~~
geofft
Rust is the first language that fixes all of these things, can be used as a
replacement for _all_ of C's use cases (including ABI-stable libraries,
kernels, etc.), and has a sufficient community / mindshare that you can expect
libraries to exist in the language for functionality that you generally expect
to find in libraries.

Maybe we should be embarrassed as an industry that it took us 20 years to get
there, yes.

~~~
beeforpork
If Rust misses 'goto', it is not suitable for translating SSA into it, which
most compilers natually produce (also for LLVM, obviously). I.e., it is not
suitable for being used in a compiler backend. Here, it can never fully
replace C.

'goto' should not be daemonized, we know better today.

~~~
eddyb
I don't follow, why would SSA need to be translated _into_ an input language?

LLVM used to have a C backend, yes, but that hasn't been maintained for a
while now.

~~~
sklogic
> I don't follow, why would SSA need to be translated into an input language?

Rust is a meta-language with very powerful macros in it.

What is a macro? Macro, essentially, is a compiler. You can have some petty
macros implementing tiny syntax sugar on top of your language, that's totally
fine, but that's not their purpose.

The real metaprogramming kicks in when you implement very high-level eDSLs on
top of your macros. And for this sort of things, having a proper compilation
pipeline is a must. Many eDSLs may end up being represented as an SSA. E.g.,
I'm doing this with a Packrat eDSL - it pays to represent its intermediate
language as an SSA for doing some high level optimisations before spitting out
the host language code.

~~~
mafribe
The compiler implementing the macros (a form of compile-time meta-programming)
should be the same compiler as that for the rest of the language.

~~~
sklogic
> should be the same compiler as that for the rest of the language

Sorry, I do not understand what are you talking about.

Of course it is the same host compiler. But, _every_ macro itself is a small
compiler. Sometimes, when your DSL is an elaborate, complex thing, the macro
itself is a complicated, big compiler.

With all the bells and whistles of a big compiler - multiple stages, multiple
intermediate representations, all that stuff. And SSA is one of the most
efficient intermediate representations ever, suitable for a huge number of
semantic classes of DSLs. So, making it harder to generate your _same_ host
language code out of an intermediate, in-macro representation does not serve
any reason, it's plainly conuterproductive.

~~~
mafribe

        But, every macro itself is a small compiler.
    

I'm not following you here. What does that mean? The macro gets expanded at
compile-time into 'normal' source code, by the compiler.

~~~
Havvy
A compiler takes a text from one language and translate it into text of
another executable language.

