I wasn't thinking totally clearly at 3am, so around 4:30 I thought of some things that I didn't ask. =)
(You may notice that I'm coming from an event-driven paradigm...I'm trying to map my understanding of how mine works onto Cells and "make sure" Cells is a superset of what I'm using).
5) Multi-method (?) calculations: I've seen simple examples in the Cells docs that show a slot being dependent on another slot. It looks like you install this computation in the "destination" slot, i.e. the one that's dependent. What if you've got a situation where you have five slots, A B C D and E, that are parts of say three different objects, O1 O2 and O3. There's one computation that needs A B C D and E, and ends up modifying slots F G H and I in objects O4 and O5. Can it be done, making a single computation that depends on many slots in different instances that then updates slots in many instances? Or do you need to decompose this computation into (complicated!) pieces to be installed in each of the destination slots (F G H and I)? Can a change in one or more of A B C D and E cause a computation that updates C D F and G? (I.e. C and D are both inputs *and* outputs of the calculation. Note that self-cycling must be avoided!).
6) Multiple "owners" of responsibility, or aspect separation: (this is related to #5 above) What if you have a normal calculation that happens 99% of the time that changes slot A into slot B (B is dependent on A). You write the formula into the slot code for B, and you're happy. But then, because of some strange requirement or other complicated design issue, you realize that B also depends, every once in a while (say 1%), on C D and E. But you don't want to stick this new computation and dependency code with the original code, because it will not only clutter reading, but also the complicated process may change in the future. So you want to keep the concerns separate, i.e. the two different "times" when B can change. Is there a way in Cells to make two different pieces of code that show two different ways that slot B is dependent on other slots?
7) "Lazy" updates: Probably a bad term for this, not to be confused with strict and non-strict argument evaluation. Nonetheless, let's say you have a slot A that depends on B C D and E. B and C are absolutely critical to A's computation, and every single time they change, you need to enforce that A is recomputed. My guess is that Cells works like this already, automatically. However, let's say D and E change their values inordinately fast, like maybe they're mouse X and Y coordinates on the screen. Let's also say that the computation for A is non-trivial, and you want to run it only when absolutely necessary. Further, although A needs the current mouse X and Y coordinates, it doesn't make sense to recompute A every time they change. Is there a way to tell Cells that A should be recomputed *every* time that B and C change, but also needs access to cells D and E while not "firing" every time they change?
Sorry if this sounds stupidly simple, but remember, I'm projecting my domain onto yours, so I'm pretty new at this.
8) Phase-based calculation, or data "wave" propagation: If a slot A depends on slots B C and D...when will A get recomputed? Every time that B C or D change, right? What if two other computations change both C and D as a result of a single slot change in E...does Cells defer the running of A until *both* C and D have been recalculated (i.e. enforced breadth-first dependency graph traversal), or will the calculation of A happen twice, once when C changes and once when D changes (i.e. random, depth-first, or other traversal)?
9) Introspection: How easy is it to determine the full dependency graph of interrelated computation given a system coded using Cells? I.e., other than of course looking at the code, can I use a programmatic method to determine the topology of the dependencies in order to, for instance, produce a visual graph of the system? Is this introspection system static, or dynamic (i.e. allow callback hooks or the like to update changes in the system as they happen)?
Thanks again for any comments.
Mike
Mike J. Bell wrote:
I wasn't thinking totally clearly at 3am, so around 4:30 I thought of some things that I didn't ask. =)
(You may notice that I'm coming from an event-driven paradigm...
No problem. I am usually developing GUI apps--all events all the time.
I'm trying to map my understanding of how mine works onto Cells and "make sure" Cells is a superset of what I'm using).
- Multi-method (?) calculations: I've seen simple examples in the
Cells docs that show a slot being dependent on another slot. It looks like you install this computation in the "destination" slot, i.e. the one that's dependent. What if you've got a situation where you have five slots, A B C D and E, that are parts of say three different objects, O1 O2 and O3. There's one computation that needs A B C D and E, and ends up modifying slots F G H and I in objects O4 and O5. Can it be done, making a single computation that depends on many slots in different instances that then updates slots in many instances? Or do you need to decompose this computation into (complicated!) pieces to be installed in each of the destination slots (F G H and I)?
You say complicated, I say "divide and conquer". Have you ever developed a finite state machine, breaking some complex problem down into a kazillion states? It seems painfully slow at first, until you realize how effortlessly the approach deals with the overall computation, which had you so confused that you resorted to using a finite state machine. :)
Cells is all about exposing the semantics of a slot in the one formula which determines the value of a slot. What you are describing is "classic" imperative programming, where this point in the code decides FGHI, another decides GH, another decides GHZ, etc etc. At which point no one can really tell us the semantics of H.
Now if you promise me that there is one and only one computation which decides FGHI, what I do in cases like that is simply create a new slot called FGHI (I wager the real name will be quite meaningful to anyone reading your code) and then F, G, H, and I can have extremely simple rules:
:f (c? (get-f (^fghi))) :g (c? (get-g (^fghi))) ..etc...
Can a change in one or more of A B C D and E cause a computation that updates C D F and G? (I.e. C and D are both inputs *and* outputs of the calculation. Note that self-cycling must be avoided!).
Again, sounds like you are resisting "divide and conquer". <g> I have been doing cells for about nine years now, and I have never had a problem decomposing big computations into so many slots mediated by so many cells. The cyclicity thing rarely materializes, but see my discussion of scrollbars in an earlier reply for how I handle that cyclic case.
- Multiple "owners" of responsibility, or aspect separation: (this
is related to #5 above) What if you have a normal calculation that happens 99% of the time that changes slot A into slot B (B is dependent on A). You write the formula into the slot code for B, and you're happy. But then, because of some strange requirement or other complicated design issue, you realize that B also depends, every once in a while (say 1%), on C D and E. But you don't want to stick this new computation and dependency code with the original code, because it will not only clutter reading, but also the complicated process may change in the future.
You say "clutter", I say "completely specified". <g> What is wrong with:
(c? (if (one-chance-in-a-million self) (big-hairy-mess (^c) (^d) (e))) (nice-and-easy (^a))))
And who cares if it changes in the future? Just maintain the formula, which will always fully document the semantics of a slot. One of the nice things about not using GOTOs is just /knowing/ without worrying that any given point in the code is always reached via visible control flow.
So you want to keep the concerns separate, i.e. the two different "times" when B can change. Is there a way in Cells to make two different pieces of code that show two different ways that slot B is dependent on other slots?
Not sure what you mean. Are you aware that different instances of the same class can have different rules for the same slot. This might help with your question above. Perhaps the rare situation is known at make-instance time? In which case you can indeed supply a different rule which goes after CDE.
- "Lazy" updates: Probably a bad term for this, not to be confused
with strict and non-strict argument evaluation. Nonetheless, let's say you have a slot A that depends on B C D and E. B and C are absolutely critical to A's computation, and every single time they change, you need to enforce that A is recomputed. My guess is that Cells works like this already, automatically. However, let's say D and E change their values inordinately fast, like maybe they're mouse X and Y coordinates on the screen. Let's also say that the computation for A is non-trivial, and you want to run it only when absolutely necessary. Further, although A needs the current mouse X and Y coordinates, it doesn't make sense to recompute A every time they change. Is there a way to tell Cells that A should be recomputed *every* time that B and C change, but also needs access to cells D and E while not "firing" every time they change?
Yes. See "synapses". I believe Bill's blog on Cells covers that, as well as some of my awful doc.
Sorry if this sounds stupidly simple, but remember, I'm projecting my domain onto yours, so I'm pretty new at this.
- Phase-based calculation, or data "wave" propagation: If a slot A
depends on slots B C and D...when will A get recomputed? Every time that B C or D change, right? What if two other computations change both C and D as a result of a single slot change in E...does Cells defer the running of A until *both* C and D have been recalculated (i.e. enforced breadth-first dependency graph traversal), or will the calculation of A happen twice, once when C changes and once when D changes (i.e. random, depth-first, or other traversal)?
Some recent work I playfully christened "Cells II" addressed this concern. Now A will be calculated only once. Each wave gets an ID (just an incremented count) and, if A gets calculated too early, no problem. The engine sees that C and/or D are obsolete (we are calculating wave N, but C and/or D are stamped N-1) and recomputes them Just In Time before completeing the calculation of A.
- Introspection: How easy is it to determine the full dependency
graph of interrelated computation given a system coded using Cells? I.e., other than of course looking at the code, can I use a programmatic method to determine the topology of the dependencies in order to, for instance, produce a visual graph of the system? Is this introspection system static, or dynamic (i.e. allow callback hooks or the like to update changes in the system as they happen)?
A visual graph would be easy to do and probably great fun to watch. I imagine little sparks shooting around, like an animation of the brain. I have long been tempted to do something like that. I guess the thing that holds me back is the problem of how to lay out the visual elements so the whole thing looks good. I always hate the way graphical class browsers end up looking.
kt