savi
savi copied to clipboard
Add linear / unique types?
Add refcap lin with the following rules:
lin! -> non
lin^ -> lin
A lin repcap would be very similar to an iso, with the only difference being that when a lin goes out of scope, it is guaranteed that no further reference to it exists (no tag references as for isos) and as such can be deallocated right away. Some advantages:
linreference would not put pressure on GC.linreferences would be deallocated predictably (compile-time known).- They could be deallocated while a behavior is running.
- Probably less inter-actor GC traffic required.
- All
linfields of a class would be deallocated right away when the class is deallocated. linreferences cannot have cycles (limitation).
Compare that to iso:
iso! -> tag
iso^ -> iso
I wonder how complicated automatic receiver recovery would be for lin references (which would basically be a limited form of Rusts borrow checker).
Maybe you already do some compiler optimizations like escape analysis etc. so that the compiler is smart enough to figure out whether an iso has tag references or not. Even if you do so, it's just an optimization and the user cannot depend on it, especially for disposing more expensive resources like Files, Sockets etc.
:class File
:var fd : Int
:new lin (filename : String)
...
:fun lin _dispose:
if (@fd > 0) ( close(@fd); @fd = 0 )
:actor Main
:new (env)
:let file : File lin = File.new("test")
...
// file._dispose called here (unless `file` is consumed before)!
lin would actually be more an affine type as it gets dropped (_disposed) automatically when not used. In Rust, you can add #[must_use] annotations to functions telling the compiler to emit a warning when a result is not being used by the caller (very useful for futures...). It would be interesting to make this distinction in the type system, so that an unused lin ref would lead to a compiler error, unless you'd explicitly consume it, whereas an aff refcap would add a _dispose call when it goes out of scope.
One thing to note here is that if we want to be compatible with the Verona runtime (which is a tentative goal right now), we will need to preclude the possibility of tag aliases of an iso anyway. And for Verona we'll also need to do the kind of static analysis needed to determine whether an iso going out of scope, transitioning to val, or getting absorbed into another isolated region.
So it's possible that the right approach is just to make iso behave in this way rather than adding a new ref cap.
Yes, that is basically what I was asking for! Just curious, but do you know the exact reasons why the Verona runtime requires tracking isos?
I don't know the full details since I've only learned what I know by reading the source code without much assistance from the Verona folks. So if this doesn't answer your question in enough detail you may need to inquire with them.
So unlike the Pony runtime, where the rcaps (mostly) don't exist at runtime, in the Verona runtime they very much do, and there is some runtime bookkeeping that is akin to shared reference counting for iso, val, and cown (actor-like objects).
Here are the reference-counting-like functions for Verona that I know of:
acquireandreleasefor reference counting of an actor/rt::Cownacquireandreleasefor reference counting ofval/rt::Immutablemerge, andswap_rootfor managingiso/rt::Regionroots interacting with each otherfreezefor turning aniso/rt::Regioninto aval/rt::Immutable
There may be more Verona bookkeeping that I'm unaware of (like for example, something akin to an explicit drop/release for iso/rt::Region like you are asking for in this ticket), but at this time, that is the summary of my limited knowledge on the subject.
Thanks a lot.
Verona PR https://github.com/microsoft/verona/pull/518 may relate to this topic.
More research is needed on what's going on there to understand the impact/potential.