I always, always forget what `'a: 'b` means, because I remember it always being the opposite of what I think it is, but memorizing that obviously doesn't work because then it will just flip again the next time. It's so annoying.
I always describe it to myself this way - T: Foo means T is a superset of Foo (because it at least implements Foo but most likely more) thus 'a: 'b means 'a is at least as wide as 'b, and possibly wider
I had the same problem until I realized this: for generics and traits T: A means T implements A and it's actually the same with lifetimes: 'a: 'b means lifetime 'a implements lifetime 'b, which naturally translates to objects with lifetime 'a lives at least as long as 'b.
I don't identify human, but you're absolutely right. For me, this also happens with the direction of hot vs cold on faucets/showers. I can never ever understand. Sometimes they're relative to the top edge and sometimes to the bottom edge. Sometimes they are on the wall/sink and sometimes they are on the actual handle. Because everything is always completely impossible to define proper rules for, the only thing I can rely on is "it's different than you thought it was before" but relying on that also doesn't work!
If you think of it as 'a implements b', it makes sense for both lifetimes and (other) subtypes: If lifetime `a` implements `b`, it is obviously valid for `b` (and maybe longer).
You have to first remember what lifetimes are there for in the first place: to indicate that values live at least a certain duration. That is what the type &'a means. Then it becomes clear what the relation 'a: 'b means
It was a good signal to me that you are overthinking into the architecture if that is really required. Rust makes something pretty much impossible in C/C++ possible, but not necessarily easy, and that would be one such example.
> It was a good signal to me that you are overthinking into the architecture if that is really required.
Sure, maybe I don't need to statically guarantee the correct execution of code that could easily just throw at runtime instead, but it sure is a fun hobby.
Lifetime subtyping is normally not much necessary to ensure the correctness, provided that you are working at the sufficiently high level (so, say, std is available) and do have some freedom in the design. It often indicates that you are excessively avoiding heap allocations.
You can't just allocate a Lua coroutine on the heap. Lua coroutines are managed by the Lua virtual machine. So that's one heap allocation "avoided". I don't remember the others off the top of my head but some functions needed to have three lifetimes for various reasons. Not sure if I eventually refactored that out or not, it's been a while. I should get back to it one day when my job isn't nothing but startup crunching