Skip to content

Instantly share code, notes, and snippets.

@ELLIOTTCABLE
Created June 22, 2010 21:23
Show Gist options
  • Save ELLIOTTCABLE/449113 to your computer and use it in GitHub Desktop.
Save ELLIOTTCABLE/449113 to your computer and use it in GitHub Desktop.

executions, first-class ghosts/futures, and multiple resultings:

well, first thoughts I had… we could have our equivalent of ‘futures’ be, well, a list… and then have results added to the future-list as they become available.

however, I think that makes it fairly inconsistent: if you utilize that list anytime between the start and end of execution, you’ll get some ‘unfinished business.’ It won’t have everything it might have later… meaning how your operation plays out depends on exactly when it happens to look at the list.

essentially, the key to Paws’ system now is that execution splits: at the routine call. An alternative to ‘futures’ (which are restricted to one value… very un-paws-y), or the above idea (a self-populating futures- list)… is perhaps to move that “execution split” later into the execution. We could make this concept of ‘a place to which the routine returns’ first-class, in and of itself… and then any place that blocks against it (that is, any place that absolutely needs its real value), is a place where execution stops, and then split-resumes whenever a value is returned.

what this would mean: a single path of execution from the routine call… possibly, itself, forking in various places… and then, at all of the terminations of that path, places where things blocked against that first-class “split object.” At those places, execution would split again, for every value the routine returned. I’ll call this “first-class ghosts” to differentiate from futures.

BUT what about the problem with the other solution? consistency? specifically, we need to ensure that whatever happens if the value of our ‘first-class ghost’ is accessed or utilized anytime during the execution of the program is the same as any other time. Specifically, if it’s accessed prior to the completion of the originating routine, the eventual result of the program needs to be identical to as if the accesses happened to come to pass after the completion of the originator.

Hence, if we use these “first-class ghosts”… they have to operate identically no matter when they’re utilized… which means that program execution has to fork wherever they are used, for every element they’ve ever had! i.e. then that our “first-class ghosts” become a sort of first-class fork in the program execution: anywhere they are referenced, the program splits into one branch for each value they ever have had, or ever will have.

BUT this is Paws… and we don’t create a tool to do one thing where instead we can create a tool to do multiple things. So, we want to abstract out this concept o first-class ghosts into a generalized tool, that we can then re-apply to the original problem… as I said above, these are sort of first-class forks in the program’s execution. Why don’t we make them exactly that? Hence, we could have a fork object, that provides a natively- implemented fork method. When called, the routine never returns (in the original thread; that is, it is a forced-blocking routine, causing the original thread to be deallocated when it is called); and proceeds to result once for every element of itself (a list, like anything else in the language). On top of this, we would change the lookup on this, libside, such that any lookup is actually preformed on all of the elements simultaneously, by forking against the elements first.

That means, that any place you use a fork (looking up values on it, calling methods on it, even comparing it against anything else that is not, itself, a fork), the program will… well… fork, and then the original action will happen for each element instead!

This is also, actually quite easy to implement as well: we already have the framework in place with our executions: we just have infrastructure fork fork() block (that will kill the calling original execution), and then have it call the calling execution once for each of its own elements. (Notice, this is practically identical to the proposed implementation of list each()-and that’s by design. The only real difference is that the fork object would pass all lookups through fork fork()).

SO, all this said: how do we map this new, generalized tool, back to our original problem? We simply create a ghost type that “inherits” from fork: it works exactly the same way. However, our ghost is implemented natively, and an opaque reference is retained to any execution that fork()s against it. Then, when new elements are “resulted” into our ghost at a later date (i.e. the originating function calls forward with new values), every place that had forked on our ghost will now fork off a new execution again for the new value.

LONG STORY SHORT: ghosts are branching-pipelines, between the originator routine and the places where they are used. Every place in the program that uses a first-class ghost gets forked-at for every value ghost has had or ever will have.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment