Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

I find it very notable that Graydon Hoare, the "founder" of Rust, went on to work at Apple on Swift for a while.

Also, Swift had tremendous work to implement ABI stability[1], which really allows it to be used as an OS API, which Rust can't do.

[1] https://faultlore.com/blah/swift-abi/



I read Graydon's recent "If I were a BDFI" essay and found myself mostly sympathizing, especially with the "I wanted Rust to have potentially costly abstractions, because that's the point of abstractions, pay a known cost to solve common problems". It seems Rust was taken over by the "zero cost abstractions at all costs" crowd. Graydon seems at peace with that because it's what the community wanted. But I think it's also obvious that he was frustrated by the regression to the mean that comes with shared ownership/leadership.

Then I thought that what we really need is a Swift-like language with the ability to remove costly abstractions when you don't want to pay the cost, but that default to ergonomically solving the problems that the majority of programs need to solve. You should opt-in to more semantic complexity, not be encumbered by it by default. Rust's obsession with performance above all else confuses me. But I also guess it's nice to have a safe space for performance sensitive programmers. But like how can a systems language not have a stable ABI? Very mixed messages.

Ultimately this "Rust with better ergonomics" language could be Swift. I do think it is more usable across platforms than people give it credit for. But it's also missing the "let me dip down into lower level but more complicated semantics when I need to" option. Having a stable ABI is awesome, though. I really can't wait for the day where I can start a portable project in Swift without a second thought.


> Rust's obsession with performance above all else confuses me.

It's kind of a requirement if they hope to replace C/C++ as a systems language, as those remain the goto answer for "I need maximum control", short of assembly.

And they want to replace C/C++ to fix all their safety problems.

I work in embedded systems, where C remains a holdout, with all its problems. Rust's performance-oriented direction makes it a viable consideration for us.


I understand the need to compete with C/C++.

My understanding of zero cost abstractions is that they predominantly happen at compile time (and thus commonly appear in language semantics or the type system) and literally cost nothing at runtime. This has other costs like semantic complexity, but almost never performance.

Regardless, I don't buy that Rust couldn’t present a more opinionated and complete programming experience without allowing the same performance characteristics that it has today. The whole async situation is awful. Lifetimes are a stupid leaky abstraction 99% of the time. My point is that there’s almost never a scenario where you e.g. need to bother with passing around a struct with a reference with a lifetime. 99% of the time you just take ownership of the data or use an Arc<Box<T>> and 99% of the time that’s not a performance problem. What I think is stupid is that Rust elevates and enshrines the 1% use cases and makes the 99% experience worse off for it. I love Rust. But it could do a better job of solving the 99% cases nicely while allowing a “zero cost escape hatch” where you could say “actually I do want a stack allocated reference without atomic reference counting” and pay the semantic price 1% of the time rather than 99% of the time, similar to Swift’s approach.

Obviously my experience had been shaped by the projects I’ve worked on. But I also think Swift is an entirely more ergonomic and practical language. If you think Rust is a viable option then, unless you’re anti-Apple, Swift with ownership semantics most certainly is too. Seriously.


But the problem with zero-cost abstractions is that even if the runtime cost is 0, the compile time (and the human time) can become quiet large.

E.g. https://www.youtube.com/watch?v=rHIkrotSwcc


Zero-cost abstractions are exactly that:

- you only pay for what you use

- if you use it, you couldn't implement it better yourself

There's no such thing as literally zero cost, obviously.

Graydon was saying that even this fairly reasonable pair of conditions got in the way of some nicer abstractions.


It worked for Microsoft VC++ for a long time.


Nowadays they rely on COM for that purpose, which is nice as idea, if the tooling wasn't so clunky.


MSVC++ 2015 or later has a stable ABI independent of COM.


I’m interested in how this works (this thread is now getting old so I’m not sure there will be replies…)

One of the important aspects of a stable ABI is the ability for clients to continue to work even after the size of a remote type changes… for instance, if Foo is a type defined in Foo.dll, and I link to it, and my code does `Foo *f = new Foo()`, the compiler will emit code that malloc’s `sizeof(Foo)` bytes on the heap. If later on, Foo gets a new member variable “m”, it will increase in size, and now code in Foo.dll will segfault if it tries to access `this->m`, if a client allocated it.

COM solves this by basically not letting you do `new Foo`, but instead you have to ask COM itself to allocate and return an instance for you, with something like `CoCreateInstance`. This allows .dll’s to evolve even if the size of the object changes, by abstracting away things like size information so that clients don’t care about it. ObjC solves this similarly with `[SomeClass alloc]`, where clients just ask the class to alloc itself and returns a pointer (which is delayed until runtime, not in the emitted code), and Swift solves it with value witness tables which delay the lookup of size/stride information until runtime.

I don’t understand how, you can write .dll’s with not only a stable ABI, but the ability to actually evolve your types, in plain vanilla C++… I think the language itself has painted itself into a corner that prevents things like this.


Yes, hence one of the reasons why WinRT came to be, as COM evolution.

You get .NET metadata, IInspectable, and an improved type system, basically .NET CLS.

It doesn't expose everything C++ can do, but enough C with classes, OOP ABI and generics.

https://learn.microsoft.com/en-us/uwp/winrt-cref/winmd-files

Basically what COM vNext was going to be, if it wasn't for .NET pivot (see Ext-VOS).

However the tooling is as clunky as using ATL.


Which is creating a bunch of headaches for full ISO C++20 semantics, and most likely needs to be fixed by when ISO C++23 gets fully supported.

One example where this shows up is [[no_unique_address]].


> which really allows it to be used as an OS API, which Rust can't do.

I think that's a massive simplification


In what way? OS API’s can’t reasonably be copy/pasted into every binary on the system. It’s one thing to have large executables for third party apps you install, but you’d get tired of the wasted disk space really quickly if every binary in the OS had to statically link in the implementation of every library it used.

It’s not just disk space either, but the ability for an OS as a platform to swap out implementations of their API’s with new ones, without requiring every app to be recompiled. It’s the reason macOS is able to implement things like dark mode, or a new UI theme, or any other “horizontal” feature that works across all apps; you need dynamic linking for that to be possible.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: