Thank you for your donations!   Download the book!   Public source code repository   Join the group!

Borrow checker strikes back

As you can tell by the updates to the repository, I was using Rust up until today. I was listening to my intuition telling me it's worthwhile. Well, maybe only for a good blog post, not sure if that counts.

Yesterday, I was hacking around some array containing chars as bytes, in short parsing plain old ASCII. At one moment, I needed one place to put recurring pattern: safely get byte 1 or 2 places from the current index; safely as in checking if index with offset points past array boundaries. So, inner function will do? Nope, functions cannot capture variables from enclosing scope, which I wanted to minimize amount of arguments. Oki, lets try closure. Yes, that'l do.

Except for one little thing. It also borrows variable, and it does not let it go, after invocation is done, and result is returned. This is a serious issue because in a sequence of statements borrow ends with last usage of variable. And, function is basically a replacement for some of (intermittent) statements. And, closure is more-or-less a simplified function. So, ending of a closure should also end all of its borrows.

Worse, variable is not handed over to some container to take its ownership; no, temporary value is calculated, then dropped after unrelated value (byte, in this case) is returned. Worse still, borrowed variable actually contains integer, which should never ever trip over borrow checker. At his point I sort-of figured it would be uphill battle with borrow checker, all the way up.

Just my personal preference, but I'd like to use language where explicit returns are not frowned upon. I mean, it's nice that Rust-peeps are trying hard to make it more convenient, but sometimes trying too hard is just too much. If you have programmed long enough, you most likely debugged some code at 03:00 (a.k.a. 3 AM, for you Americans out there), when all of the code starts to look like this:

mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmnmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmwmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm

Can you spot 'lil bugger in there? No, not that one, the other one? And if only difference is presence (or absence) of ; (semi-colon) at the end of some line in a function ...  as some might say, lykke til med dat.

Also my personal dislike, but I don't want my code to panic. Panicking is emotional response, it has nothing to do with how one will respond. Worse, it conveys uncertainty about its responses, sometimes it might crash, at other times in the same situation it might produce a message, or even full back-trace. I'd prefer my code to exit, quit, or just plain old crash; but never to panic.

Add to this remark from the Rust book that in the beginning Rust devs were writing lifetimes everywhere (!?), and that now it's much less needed, and in future it might be even less so; and you get the impression that fundamentals are not thought through. 

Which brings me to the infamous 1.0-curse. At the moment, Rust is at 1.50.0, which makes it legacy code, where maintenance and compatibility takes over development, so updates are bringing only incremental improvements over already existing base. Sooner or later, to make real progress, one has to resolve fundamental issues, which means braking things before redesigning them, sometimes even foregoing most of past efforts put into it.

The larger the project, and organization behind it, the harder it is to take the plunge. Given that the Rust Foundation is backed by 5-6 large corporations, most of which are for-profit, and you can reasonably expect those fundamental issues never to be resolved. 

Which is a shame, and a bit sad at the same time. Rust was first, and still is the only one to formalize ownership of data, and accompanying (mutable) borrow, without garbage collector, with very-little-to-no run-time penalties, with speeds comparable to the venerable C language; which is also much easier to write and read (and understand); a mighty feat, indeed!

Still, I can only work with what is available now, and can't rely on what will be one day. So, I started looking at alternatives. Currently, I'm looking into D. Probably the only language that had 3 (!) standard libraries at the same time, Phobos, Deimos and Tango; in the end Phobos emerged as the standard library. I can already hear early 2000's calling, and they want their bigger-better-C(++) back. Since it's still around and kicking, that qualifies it. After all, bigger-better-C(++) is bigger, and better C/C++, right? Might be fun, we'll see.

No comments:

Post a Comment