HPInc / HP-Digital-Microfluidics

HP Digital Microfluidics Software Platform and Libraries
MIT License
3 stars 1 forks source link

Add future types to DML #283

Open EvanKirshenbaum opened 8 months ago

EvanKirshenbaum commented 8 months ago

When looking at how to support paths in a way that users can wrap their heads around (#282), one of the hardest questions was "How does the user split a single drop in two and do something with each resulting drop?"

The answer I've come up with is to take advantage of Delayed[T] and add a new meta-type, future T to DML. This would be something that can hold a T (and which has a value attribute that can be queried, i.e., has a value), but which actually holds a Postable[T] and which converts to a T by waiting to get a value. This would allow something like

future drop 2;
[[
    drop 1 : walk_to_position : (split north as drop 2) : more_stuff;
    drop 2 : walk_after_split;
]]]

The two paths work in parallel, but walk_after_split doesn't happen until the split is done.

If I'm going to do this, it should generalize to any type, because doing so gives me the ability to have out parameters. The basic notions are

EvanKirshenbaum commented 8 months ago

This issue was referenced by the following commit before migration:

EvanKirshenbaum commented 8 months ago

I think I'm going to delay dealing with future parameters for a bit, because the correct behavior will depend on whether the function is expecting to produce a value using the parameter or to wait on a value being produced by the parameter. In the former case, the provided argument should be contravariant with respect to the declared parameter type, and in the latter it should be covariant. So I will probably have to add some sort of in or out specification, and that's more than I need to support paths (#282), which is what I really need at the moment.

Migrated from internal repository. Originally created by @EvanKirshenbaum on Jul 05, 2023 at 10:41 AM PDT.
EvanKirshenbaum commented 8 months ago

The most straightforward way to support future types would seem to have future T convert to T by waiting for the value. Unfortunately, Type.convert_to() assumes that it's an immediate action, so in order to support this, I'll have to change convert_to() to return a Delayed object.

Migrated from internal repository. Originally created by @EvanKirshenbaum on Jul 05, 2023 at 11:00 AM PDT.
EvanKirshenbaum commented 8 months ago

Okay, that wasn't too bad. DML now supports

future drop;
future drop : up : right 2;

The latter form creates the variable immediately, and then performs the injection, which will wait for it to get the value. Note that because the declaration doesn't end until the injection does, this should only be done in a parallel block (at least until tasks are implemented (#286).)

When a future-valued variable is read, the read doesn't complete until a value has been asserted, and the value is of the contained type. I decided that the write-once notion was confusing (I may revisit this), so you can assign multiple times. Note that setting an already set future variable won't trigger anything, since anything waiting on the future would already have triggered.

You can also reset the value to unbound. There's currently no way to do this from DML, but if I can figure out how to do it, I may want to have this happen when a path (#282) includes the notion of merging into another drop, walking with it for a while and then being split out again to walk further. To support this, I'll probably need to have some notion of the drop knowing what future drops it's assigned to and having the merge reset them. (I guess that should probably happen for any variable.)

The current implementation complains "not yet implemented" on