Live data from Hacker News

Things Rust shipped without

graydon2.dreamwidth.org

151–160 of 330 posts

Re: Things Rust shipped without

#151
post #60

Earlier quoted context omitted.

Coroutines, Go style.

M:N threads didn't work for Rust, and they don't have that many advantages anyway even in languages where they do work. There has been a lot of discussion on this over the years and this has been the conclusion everyone came to.

Funny, co-routines have been recently added to C++ and they work wonders. D has fibers which are used extensively and once again, it's a highly desired feature. Go is kind of the poster boy for coroutines and I doubt anyone claims that it doesn't provide many advantages.

To be honest it seems to me like your explanation is an attempt to downplay just how nice fibers/coroutines are rather than acknowledge their utility in many existing languages.

Re: Things Rust shipped without

#152
post #148

Earlier quoted context omitted.

M:N threads didn't work for Rust, and they don't have that many advantages anyway even in languages where they do work. There has been a lot of discussion on this over the years and this has been the conclusion everyone came to.

> they don't have that many advantages anyway even in languages where they do work. Are you sure about that? One of the main advantages of coroutines/greenlets IMO is writing simple and straightforward blocking code (e.g. an echo server); without them, you either need to use threads (which are slower and much more heavyweight) orcallbacks or related constructs (async/await, futures, ...).

Threads aren't that slow on Linux. The main advantage of M:N threading as implemented in Go over 1:1 is that spawning is fast and doesn't use much memory, because you can avoid the syscall and only a small (initial) stack is required. Rust can't do the latter because it's not GC'd.

Even if it could, many real-world servers actually do non-trivial work in their threads, so the cost of spawning a thread is dwarfed by the actual work the thread ends up doing. There are serious drawbacks to M:N: complexity, fairness, problems in interoperability with the 1:1 world (including essentially unavoidable performance problems with the FFI), etc.

Re: Things Rust shipped without

#153
post #101

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.

Serialization is usually done better with macros, for performance reasons. We now have Erick Tryzelaar's fantastic serde library for high-quality serialization, competitive with rapidjson.

Re: Things Rust shipped without

#154
post #104

Earlier quoted context omitted.

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

Still, there are cases where fall-through can be useful: int remaining = length % 4; switch (remaining) { case 3: h ^= (data[(length & ~3) + 2] & 0xff)

Usually I would just factor out the guts of the expression into a little closure in that case. (let f = |x| h ^= ... x ...) LLVM should inline it just fine, and it'll save you typing.

Re: Things Rust shipped without

#155

Earlier quoted context omitted.

Man. The documentation did not make that clear at all. Was this added in 1.0? A question (In C++ syntax, as I'm not a Rust programmer): How would one call Animal::talk inside Dog::talk? The obvious thing (commenting out the println and adding Animal::talk(self) ) causes infinite recursion. The other vaguely obvious thing ( Animal.talk(self); ) is a syntax error, which makes sense. Edit: I'm referring to the code at t…

The feature was added way before 1.0, if you're talking about the documentation, then I have no idea. There is no way to call the overwritten `Animal::talk`.

I thought you could do this:

  Animal::talk(self);

Re: Things Rust shipped without

#156

Earlier quoted context omitted.

> The ability to provide a default implementation of a function in a trait that can be inherited and used by "classes" that extend that trait. Rust provides this. E.g., the "talk" method in the "Animal" trait below: [0] trait Animal { // Static method signature; `Self` refers to the implementor type fn new(name: &'static str) -> Self; // Instance methods, only signatures fn name(&self) -> &'static str; fn noise(&self…

Man. The documentation did not make that clear at all. Was this added in 1.0? A question (In C++ syntax, as I'm not a Rust programmer): How would one call Animal::talk inside Dog::talk? The obvious thing (commenting out the println and adding Animal::talk(self) ) causes infinite recursion. The other vaguely obvious thing ( Animal.talk(self); ) is a syntax error, which makes sense. Edit: I'm referring to the code at t…

No, this feature has existed a long time. Here's a post from 2012 showing it's use: http://pcwalton.github.io/blog/2012/08/08/a-gentle-introduct...

Re: Things Rust shipped without

#157

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.

Rust has an `unsafe` keyword, but goto isn't one of the things it enables.

Re: Things Rust shipped without

#158
post #105

Earlier quoted context omitted.

What the parent said still applies in your case. You just make a wrapper function that does the cleanup. I have used this pattern many times: static int foo_impl(int arg, int **resource1, int **resource2) { *resource1 = (int *)malloc(sizeof(**resource1)); if (*resource1 == NULL) return EXIT_FAILURE; /* Do something with resource1 (omitted)... */ *resource2 = (int *)malloc(sizeof(**resource2)); if (*resource2 == NULL)…

I know it is just an example to illustrate the point but this seems to have a bug in it: resource2 won't be initialized if the function fail to allocate resource1 so resource2 will be null when the code enters the deallocation condition. A way to fix it would be to return different failures for every allocation and to use a switch without a break to clean up, something like: switch (ret) { case EXIT_SUCCESS: free(res…

Passing a null pointer to free() is perfectly safe, and in this case simplifies the cleanup code.

Although the concern of a memory leak is valid. I would have expected the resources to be free'd regardless of the result.

Re: Things Rust shipped without

#159
post #120

Earlier quoted context omitted.

> The addition of some orderly construct for this in C would eliminate that case, leaving no real role for goto there either. I like the way this is handled in Go with the defer keyword: https://blog.golang.org/defer-panic-and-recover This construct gives you most of the power of C++ RAII without the overhead. Except that you can't use it to cleanup resources after exiting an anonymous block—it strictly defers to fun…

defer has unavoidable runtime overhead due to its dynamic semantics. It's strictly slower than RAII as implemented in C++ or Rust.

That's not true. The only case where the runtime overhead is unavoidable is calling defer in a loop, because it might require allocating the defer chain in the heap; in all other cases, it's just a metter of writing the correct optimization passes in the compiler.

Re: Things Rust shipped without

#160
post #101

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.

Serialization is usually done better with macros, for performance reasons. We now have Erick Tryzelaar's fantastic serde library for high-quality serialization, competitive with rapidjson.

Oh, serde is interesting. I was specifically thinking about compile-time reflection but apparently rust's macros are more powerful than I realized. I'm inspired to look into this more, thanks!
Post reply on HN