SodiumFRP / sodium

Sodium - Functional Reactive Programming (FRP) Library for multiple languages
http://sodium.nz/
Other
851 stars 140 forks source link

Optionally include debug information when constructing FRP graph #123

Open jam40jeff opened 6 years ago

jam40jeff commented 6 years ago

While debugging FRP logic, it is dificult to figure out what path the logic took through the FRP graph from the stack trace. The primitives should optionally capture stack information when they are constructed (only if a compiler flag is set as this would affect performance) so that this information can be relayed back to the developer while debugging.

jam40jeff commented 6 years ago

@the-real-blackh Do you have any thoughts on this? My goals for this are:

(1) The obvious...provide useful trace information to the developer debugging FRP logic. (2) No change to the public API. (3) Only include this information if the developer has compiled their code with a certain compiler flag set so this must be intentionally enabled. Release builds should not include this information so performance is not adversely affected.

As to (3), do you have any preference for reusing a flag such as DEBUG? Or would you want a new Sodium-specific flag to be defined so we aren't forcing all Debug builds (which some people may be using in production code) to take this performance hit?

Also, as far as (2) goes, I know in the past you have mentioned allowing the developer to include some description of the "meaning" of the primitive to get better trace information. Do you prefer this to the stack trace alternative (or in addition to it)? It would change the public API, but we could do something like make it an optional parameter so that current code would still compile.

the-real-blackh commented 6 years ago

If your language's compiler is able to tell you the source code location of the primitive, then that's great - you can use that. I have no preferences whatsoever on how that's implemented on each language.

My thought was - when you don't have that kind of compiler support - to have a new primitive called annotate:

Cell annotate(Cell c, String text); Stream annotate(Stream s, String text);

What this will do is add a label to the single node of FRP defined by the cell or stream passed as an argument. This won't affect performance much when debugging is disabled, because it would just be a no-op.

If you wanted to annotate a whole section of graph all at once... let's say you have a function that has several inputs and several outputs. You'd wrap all the inputs with from and all the outputs with to:

Cell from(Cell c); Stream from(Stream s); Cell to(Cell c, String text); Stream to(Stream s, String text);

to() would then walk the tree and stop when it sees a from(). If it sees another to(), then it would create a stack, and would need to hit two from()s. This would enable you to annotate all the nodes within that function, and the annotations would be additive.

Maybe not a perfect solution, but it's the best I've been able to come up with.

jam40jeff commented 6 years ago

This is related to #60 and may cover sub-item (3) of that issue.