Live data from Hacker News

Things Rust shipped without

graydon2.dreamwidth.org

291–300 of 330 posts

Re: Things Rust shipped without

#291
post #147

Earlier quoted context omitted.

Non-lexical lifetimes/borrows. This is a dealbreaker IMO.

For those who are not so Rust inclined, can we have an example of what this means?

Currently, lifetimes are based entirely on lexical scope. So for example, this doesn't work:

    fn main() {
        let mut x = 10;
        let y = &mut x;
        *y = 11;
    
        println!("{}", x);
    }
This will complain

    error: cannot borrow `x` as immutable because it is also borrowed as mutable
This is because an `&mut` borrow is exclusive: while `y` is alive, we cannot use `x`. We can fix this by making a new scope for `y`:

    fn main() {
        let mut x = 10;

        {
            let y = &mut x;
            *y = 11;
        }
    
        println!("{}", x);
    }
This works, and will print `11`.

Non-lexical lifetimes would allow the compiler to demonstrate that these two things are the same, and allow the first one to compile with the behavior of the second.

It's an interesting tradeoff, because right now, the rules are very simple and conservative. Scope is fairly easy to reason about. Non-lexical lifetimes would make certain things easier, but also a bit harder to reason about, because the rules are more complex.

Re: Things Rust shipped without

#292

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.

I think of the inforcing of style (snake_case CamelCase) is great, because it makes code more readable.

Re: Things Rust shipped without

#293

" 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 tr…

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.

Re: Things Rust shipped without

#294

Earlier quoted context omitted.

> 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 macro…

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.

> 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.

Re: Things Rust shipped without

#295

Earlier quoted context omitted.

For those who are not so Rust inclined, can we have an example of what this means?

Currently, lifetimes are based entirely on lexical scope. So for example, this doesn't work: fn main() { let mut x = 10; let y = &mut x; *y = 11; println!("{}", x); } This will complain error: cannot borrow `x` as immutable because it is also borrowed as mutable This is because an `&mut` borrow is exclusive: while `y` is alive, we cannot use `x`. We can fix this by making a new scope for `y`: fn main() { let mut x =…

Could you elaborate on or link to a more detailed tradeoff?

I want memory safety with as few hazzle as possible and that Rust doesn't understand the safety of the first example means hazzle. I expect the compiler to try to understand even if it's ’hard’. It doesn't need to understand everything but the mentioned situtation should be doable.

Re: Things Rust shipped without

#296
post #295

Earlier quoted context omitted.

Currently, lifetimes are based entirely on lexical scope. So for example, this doesn't work: fn main() { let mut x = 10; let y = &mut x; *y = 11; println!("{}", x); } This will complain error: cannot borrow `x` as immutable because it is also borrowed as mutable This is because an `&mut` borrow is exclusive: while `y` is alive, we cannot use `x`. We can fix this by making a new scope for `y`: fn main() { let mut x =…

Could you elaborate on or link to a more detailed tradeoff? I want memory safety with as few hazzle as possible and that Rust doesn't understand the safety of the first example means hazzle. I expect the compiler to try to understand even if it's ’hard’. It doesn't need to understand everything but the mentioned situtation should be doable.

> Could you elaborate on or link to a more detailed tradeoff?

I'm not sure what you mean by a 'more detailed tradeoff.' You mean a more complicated example?

> I expect the compiler to try to understand even if it's ’hard’.

It's not a matter of difficulty, exactly, it's a matter of how easy it is to understand what the compiler is doing. Figuring out non-lexical scopes means that my mental model of what the compiler is doing is more difficult than it is right now, which may or may not be the right tradeoff. I would say that most people want non-lexical lifetimes/SEME regions to be implemented, though.

Re: Things Rust shipped without

#297

" 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 tr…

I know that Rust has warts. That doesn't mean it has to have the same warts.

Re: Things Rust shipped without

#298

Earlier quoted context omitted.

Rust should have untagged unions. Obviously, ones that allow pointer abuse would be restricted to code marked unsafe. Note that a union of two pointer-containing structs is safe as long as the pointers line up, having the same type and offset in each struct.

Do you have a compelling use case? I can't imagine a use for untagged unions in Rust that isn't subsumed by other features in the language.

I can think of many, mostly revolving around cases where the tag is not stored inline with the structure in question. Where space efficiency is important this is quite common. C interoperability is obviously another important use case (the current solution of passing around [u8] arrays is pretty atrocious).

Re: Things Rust shipped without

#299
post #12

What about things that Rust shipped without that should have been included?

A requirement to stick #version 1.0 at the top of code files so we know which version they were intended to be compiled with, such that in future we can introduce breaking changes into version 2.0 and still have support for compiling legacy 1.0 applications.

Seriously, nearly all data storage formats we use today have some kind of version number in them - why are we treating code as dumb text rather than interesting data?

Re: Things Rust shipped without

#300

Earlier quoted context omitted.

> Yes, there may be exceptions when this kind of code is preferable. In my practice these exceptions are ubiquitous. Multiple tiny interpreted DSLs (which cannot be compiled more efficiently for the latency reasons), efficient protocols, all that stuff. System programming, in other words, and it's exactly the stuff Rust was supposed to be designed for. > But it's definitely not the rule and the speed difference betwe…

2-4 times is a spectacular speed-up, of course the inner loop of an interpreter is important but you're implying the rest of the code-path is only 3-4 instructions long (otherwise you can't get that kind of speed-up) which I find hard to believe. Even the inner loop of an interpreter usually calls routines that are longer than the inner loop itself. Is there a particular benchmark you have in mind for that 2-4 number…

Take a look at the OCaml bytecode interpreter: case bodies are all very small there, so the instruction dispatch time really counts. I got this 2x times difference when comparing this bytecode interpreter built with and without computed goto, but I don't remember any other details at the moment. In my own bytecode interpreters the difference was up to 4x, again, because each bytecode instruction implementation was tiny and trivial (like, move something from one register to another, or perform an arithmetic operation).

> Even the inner loop of an interpreter usually calls routines

These are too high level interpreters for the too dynamic languages, they're beyond any hope in terms of performance, by design. I'm talking about some simpler and better designed things (like OCaml, for example).

Post reply on HN