Programming Language Design 2020-08-03

By Max Woerner Chase

I realized that, rather than Rosetta Code, Project Euler would probably be a better starting point, because it offers challenges in a specific order, and there are multiple ways to approach them. I messed around with the first challenge, and this got me inspired enough to draft a bunch of rough ideas for standard library-y stuff. However, there was one thing that I punted on that I want to try to work out in this post.

I kind of punted on mutability. When I write code, I'm very in favor of immutability, but I feel like this project could do with mutability; I'm not sure why. Rust-style static lifetimes are cool, but I'm not ready to try to implement them. As I see it, that means my choices are "dynamic ownership", "Python-style mix", or "everything mutable". Speaking as someone who writes Python like attr.evolve(obj, field=obj.field + (new,)) (or attr.evolve(obj, field=obj.field.append(new))), I don't want a Python-style mix. I think some kind of ability to "lock" data strctures would be helpful for correctness, though it might turn out kind of fiddly in practice; we'll see.

Here's what I sort of imagine, and this might be totally off... Let's swipe some ideas from Rust. We could think about the default version of a type as "owned". Given a value of a type, there must be exactly one reference to that value by that type. From an owned value, we can take "shared" and "exclusive" references. Now as I say this, in a dynamic ownership kind of situation, it's pretty annoying to be constantly destructuring your compound data, so accessing fields or parts of a container should somehow default to shared references, with an option to get out an exclusive reference instead. I'm not quite sure what an explicit destructuring would look like, but these ideas kind of imply it has to exist.

Now, accesses and iteration and such might need to be defined in terms of reference types, so that iterating over an exclusive reference produces exclusive references, and shared produces shared. It'd be cool to have this kind of correspondence "for free", but I don't know if that's actually possible. One thing that I kind of decided here is that there isn't "destructuring iteration". I think I'm fine with that.

I'll have to adapt the code I have so far to reflect these ideas, and see if it still makes sense. I think it might be possible to get some correspondences for free. Basically, and I'm not totally confient in this idea, but I'm not sure what could go wrong, associate trait definitions with types of reference, so that there could be separate "index" implementations for shared and exclusive references. As I think about this, I realize that I'm wanting implementations for shared references to act as fallbacks for exclusive references. That seems a little iffy. According to my intuition, it shouldn't hit a situation where, given several choices, it somehow picks "the wrong one", but weird, gnarly edge cases can pop up seemingly anywhere. I'll need to consider this while being better-rested.

Good night.