Borrow/move/closure symantics are driving me to my wit's end


The fundamental problem here is that adding features to a language design is rarely a pure gain. It’s usually a tradeoff; a gain and a loss; a movement in design space. Well, there’s a philosophy that Rust should try to “bend the curve”, to adopt unique designs that tweak existing ideas to reduce drawbacks; but there’s always some drawback.

If you add sigils, even optional ones, people will write code that uses them, which might be nice for them but creates confusion for anyone reading the code. (Actually, Rust is less prescriptive than other languages here. You can create your own sigils system using procedural macros, if you really want – whereas the horror that some people feel at that suggestion has inspired many languages to purposefully omit macros.)

If you add global type inference or duck-typed generics, people will use them, and complain about mysterious errors and long compilation times. (Anyway, they already complain about long compilation times, so one should hesitate to suggest features that would further increase them.)

If you add an option to disable the lifetime checker… well, that’s one case where the needs of one use case are completely different from the needs of every other use case. There are a lot of those. Embedded/OS people want inline asm, and can’t understand how a language with all these other low-level features could consider it low priority. Server people want asynchronous or green-threaded IO, which in other environments is useful but far from essential. And in your case…

Game development is pretty much the only industry left where security is considered not that big a deal. Where the concern from memory corruption is crashes, which can be tamed empirically through thorough testing and tools like valgrind – as opposed to security vulnerabilities, which rarely reveal themselves in non-specialized testing (because they typically rely on some sort of nonsensical input data), and which frequently lurk in even high-quality C++ code with lots of tests.

Considering how many games connect to the Internet these days, I’m not sure whether that attitude is truly justified anymore. But perhaps it is in some cases, especially if the performance requirements mean there’s little alternative. Problem is, as you said yourself:

if the ‘good’ way to do thing is laborious, people will take shortcuts.

Coming from other programming languages, Rust users invariably try some familiar pattern only to find that the borrow checker doesn’t like it. If the language had a “just let me do it anyway” option, I suspect a very substantial portion of Rust code would end up using it extensively. And of that, a significant fraction would be actually dangerous, possibly exploitable, which ruins one of Rust’s biggest selling points. In lieu of that… well, some people leave, but others figure out how to design their code so that Rust’s type system is capable of proving it correct.

But even there, Rust isn’t really all that prescriptive. unsafe exists, and raw pointers are not that unergonomic. If you can’t stand writing *, you could always create your own wrapper type that implements Deref.

In general – I’m not saying the language can’t be improved. There are some features that everyone agrees should be in Rust, but aren’t there due to either implementation difficulty or difficulty pinning down an exact design. There are other features which today skeptics object to, but which, if they were implemented and everyone got experience with them, people would quickly realize were worth having. That pattern is borne out through history here and elsewhere, including as you pointed out with auto etc. in C++. But then there are features that skeptics are right to object to, and I don’t purport to be able to distinguish between the last two categories.

I’m not trying to lecture you, either. You’re performing a valuable service by making suggestions, and precisely because of what I said before about use cases, it’s important to have different perspectives. Still, even in a language like Rust, sometimes not having something is more valuable than having it.