The Language That Never Was | Celes' Ramblings
The Language That Never Was | Celes' Ramblings
The Language That Never Was | Celes' Ramblings
The Language That Never Was | Celes' Ramblings
The Language That Never Was | Celes' Ramblings
Long but a very good blog post. I largely agree with all the conclusions and similarly wish Rust would go in a better direction with regards to certain features, especially compile-time reflection.
I also sadly agree with the comments on the Rust leadership. My personal experience with contributing to Rust has not been great, though I haven't tried very hard (but exactly because the initial feeling was not great).
I feel like Rust is the initial implementation of a great language. It's all there, but some of it feels harder to use than necessary.
My wishlist includes reflection, easier to use generics, more approachable concurrency handling, and nicer string abstractions.
[Begin Soapbox]
[End Soapbox]
I mean, it's kind of the whole point of this article, to explore why they felt it was a good idea to try to create a programming language. Bashing other languages and coming up with reasons why none of the existing ones would do, is kind of the whole point. And they do self-reflect and admit that their reasons were ultimately not good enough from a purely objective point of view.
Honestly, my whining isn’t aimed directly at this piece, but to vent my spleen about yet another “Python is slowwww…” missive that is filling the internet.
Theirs comes across to me as “Every language is not good enough for me” whine. Two whines passing in the night, mine and theirs.
Thanks for taking the time to make a good point and apologies for my hypocritical whine about whining.
There is only one mention of Python being slow, and that's in the form of a joke where Python is crossed out and replaced with "the wrong tool for the job." Elsewhere in the post, Python is mentioned more positively; it just isn't what's needed for the kind of gamedev the author wants to do.
OP wants to build a game. When I build games, I start high level (Python, Lua, GDScript, etc), then move the slow, stable bits to something faster. That's a really effective flow, and at the end, I get a great scripting interface for my game.
But then, given the complaints, I'm not actually sure they do want to build a game, I think they really want to build a language, and maybe an engine.
… I start high level (Python, Lua, GDScript, etc), then move the slow, stable bits to something faster. That’s a really effective flow, and at the end, I get a great scripting interface for my game.
That’s the way to do it. “Premature optimization being the root of all evil” and all. Something that is slow but works is always better than something fast that doesn’t.”
But then, given the complaints, I’m not actually sure they do want to build a game, I think they really want to build a language, and maybe an engine.
And there’s nothing wrong with that. I personally find no interest in programming for programming’s sake. I need a problem to solve first. But what if I don’t have a problem to solve? Create one! Generating a problem is a valid way to let myself “enjoy” the combined agony/pleasure of programming.
TL;DR - I didn't read the whole thing, but I couldn't help but ask about the elephant in the room: Lua (or another fast scripting language).
Here's the workflow:
You get most of the benefits of Rust, hot reloading, etc, precisely what OP was asking for. You can even use Lua code to break the rules in Rust.
Yes please!
Yeah, that always struck me as stupid.
As long as it's not allowed for "production" builds, I don't see an issue. Why not just have a compiler flag or something that turns it on or off? Then you can be ergonomic in development and principled in production.
The note about WebAssembly is odd, it's just slapping a fresh coat of paint over the same abstraction. If you're communicating with part of your app in WA, congrats, you have a crappier version of the same thing. WA is cool and can be part of the solution, but let's not clutch our pearls here.
Isn't that what lifetimes are? You're proving to the compiler that this can be a value type given it's known lifetime. If you don't know how long something will live, it has to go on the heap or you can have memory safety issues.
I agree and disagree here. On one hand, I do a lot of web dev, so async is really nice in keeping things fast. On the other hand, mixing the two sucks.
Here's my wishlist:
Yeah, the borrow checker is a bit too strict IMO. Ideally, the borrow checker would only trigger on things that could be run in parallel, such as with threads or async.
That said, I haven't had many issues, but I also don't make games. Generally speaking, copying is fine, which lets you have one place for doing modifications if you can send modifications to some kind of store.
All that being said, I feel like the real problem here is that OP wants one tool to solve the complete problem. They brush off WebAssembly for some reason. They don't consider writing a portion in a scripting language. They don't consider a microservice architecture, where parts can be hot swapped. Etc.
Rust is great at things it's great at, so use it for those. Build a system that has stable parts in Rust and unstable parts in something easier to iterate on.
I didn't read the whole thing, bit I got pretty far. Maybe I'll finish later, idk.
It is necessary to guarantee consistency in the trait system, otherwise it could lead to memory unsafety. Even relaxing it in cases where overlapping implementations could always be catched is still problematic because the compiler sometimes performs negative reasoning about traits that it know cannot be implemented downstream due to the the orphan rule.
And if you think about it the orphan rule is not worse than what other languages allow. For example C# only allow implementing an interface when defining a type, while the orphan rule also allows you to implement a trait when defining the trait itself. Not to mention being able to implement a trait only when a generic parameter implements another trait.
You can still trivially violate memory safety without multithreading or concurrency. The article touches on this a bit (they mention e.g. iterator invalidation) but they fail to address all issues.
https://manishearth.github.io/blog/2015/05/17/the-problem-with-shared-mutability/
Sure, but that doesn't mean it can't be better.
Surely the compiler could delay optimizations until the entire project is built, no? Then it knows what implementations exist, and the developer could then decide how to deal with that. Perhaps the dev could decorate the trait impl as overriding all others, overriding one specific impl, etc.
The orphan rule feels like throwing the baby out with the bathwater.
Sure, and ideally those cases would be accounted for, or at the very least the dev could annotate each use to turn the borrow checker off for each instance, and that could print something at build time and a linter could flag over it. Unsafe blocks aren't feasible for everything here.
A lot of these situations are fine in practice. Give devs the ability to sidestep the rules and take responsibility for the outcome.
@sugarinyourtea @SorteKanin Tried to script with Rhai. Got bitten by the fact it doesn't support async.
The orphan rule is not stupid, it is necessary.
My understanding is that it's necessary given the current design of the compiler. That doesn't mean it can't be removed at some point.
It would be really nice to be able to define trait impls wherever, and it should be possible.
Lua has a really good C api. Not sure if there's anything for rust.
mlua looks nice. It also does async for coroutines, which is really nice.