I am toying with a non-trivial Rust project to get a feel for the language.
There's a pattern I keep seeing in my code which isn't easy to express in
Rust. I wonder what the "right thing to do" is here.

The pattern is as follows. I have some container, which contains some
components of different types. The container as a whole is send-able . The
components form a complex graph (with cycles).

What I'd like to do is something like this:
- Declare a pool of objects of some types, which is held by the container.
- Declare pointer-to-object whose scope is the container; that is, the
lifetime of the pointer is the lifetime of the container. The pointer can
be freely passed around, cloned, etc. but (for mutable objects), only one
mutable access is allowed at a time.

This calls for something between GC pointers and RC pointers. GC is out,
because it isn't send-able. RC is out, because it doesn't allow for loops.
So right now I use explicit pools and a semi-safe (that is, unsafe...)
"smart pointer" type. And I don't support dropping objects until the whole
container is done (which is OK in my specific app but isn't really a good
solution).

Ideally what I'd like to see is separating heaps from tasks. That is,
suppose that GC pointers had a heap attribute (like borrowed pointers have
a lifetime attribute). By default, each task has a heap, but it is also
possible to define additional heaps (like we have the static lifetime and
can also define additional lifetimes).

So, the container could hold a heap and then many components with
heap-scoped pointers. The whole thing is send-able and GC is done in the
scope of each heap on its own (like today).

There are implications on the type system (no mixing pointers between
different heaps, unless the heaps are nested) - this seems very similar to
the lifetimes type checking...

Overall this seems very symmetrical with lifetimes. Basically, lifetimes ==
static (compile-time computable) free/malloc; heaps == dynamic (run-time
computable) free/malloc.

One interesting pattern allowed by this is ad-hoc actors (there are others
of course). Currently, if one wants to write actor-style code, one ties in
the GC pointers to one heap of one actor, which means one forces the
parallelization policy to one task per actor. One could argue that the
run-time should be good enough that any aggregation of actor threads to OS
threads would be done optimally (which is a good goal); but in some apps,
to get good performance one would like to control this. If we could
separate heaps from tasks, we could spawn fewer tasks (roughly the number
of OS threads) and use application code to decide which actor runs when and
where (e.g., in combination with thread affinity to ensure better cache
locality).

At any rate - is this something that makes sense in the Rust view?
If so, is there a chance of something like that being added (a completely
separate question :-)?
_______________________________________________
Rust-dev mailing list
[email protected]
https://mail.mozilla.org/listinfo/rust-dev

Reply via email to