Awesome! Thanks.
What do you think about
?
Awesome! Thanks.
What do you think about
?
I have mixed feelings.
At first glance, it looks quite innocent.
but can be expanded to
I can't see duplicated entries, while traversing stack with the "caller of the caller" chain.
I'm not sure if my example procedure is truly non-tail recursive.
Because you're showing error messages, you're not using script pics, so I can't read your procedure.
I'm confused; you have a block named non-tail that has the code from the tail recursive block. Maybe it's because I made a script pic for the second one by reusing the editor from the first one. Let me try again...
Try that...
Yeah, the first script pic just had a report block, and the second script pic had the first script.
Here's what I get when I force an error when it reaches 0.
Huh. I wonder how that works? Snap! can't forget about all the recursive calls, because after each one it has to add 1 to the result before reporting to its caller. That may be even clearer in a case like this:
triangle 5 ➞ (triangle 4)+5
triangle 4 ➞ (triangle 3)+4
triangle 3 ➞ (triangle 2)+3
triangle 2 ➞ (triangle 1)+2
triangle 1 ➞ 1
∴ triangle 2 ➞1+2=3
∴ triangle 3 ➞3+3=6
∴ triangle 4 ➞6+4=10
∴ triangle 5 ➞10+5=15
When we reach the base case we have to remember that we still have four additions to do, in order to compute triangle 5.
So I wonder why those aren't showing up in your stack display. They should, so the user can see the values of variables in the intermediate calls before the error happens.
There is a link to the project https://snap.berkeley.edu/snap/snap.html#present:Username=dardoro&ProjectName=debug.2&editMode
Maybe "this(Caller)" stored in the environment is lexical information.
The runtime stack may be burried down into parent, home, and outer contexts.
Also, the process was already stopped before the error message.
Yeah, that's always a problem for after-the-fact debugging. In a perfect world, there would be a "Pause on error" option in the settings menu that would preserve all the dynamic information when an error happens. We did that in Logo and it was great; you could use Logo itself as the debugger.
How about using try safely …
?
Remember, we were thinking about that in the streams library, and it turns out that that library catches only JS errors, not the errors that Snap! finds by itself. Having one that works 100% is on my "Jens thinks it's too hard" list.
Does it?
A different approach
For debugging purposes one could (temporarily) insert a script registration block into each custom block’s definition:
(with current script
being a global variable)
Thus if a script crashes one can reconstruct the environment at the time of the crash - at least if only one thread is active.
Demo
This example block has an embedded current-script-registrar (CSR):
When an error occurs Snap!’s default error message appears:
One may now inspect the environment where the error occurred, e.g.:
Automation
I can imagine a block that will insert a CSR at every custom block definition that doesn’t have one yet, and a second block that will remove any of these CSRs. I challenge readers of this post to build such blocks.
report
block, the report
part will be left out of the decomposition.These are rather weird features from a user’s point of view (probably there’s a historical explanation for each of them, such as how it’s done in Scheme, or they make code easier to execute for an interpreter); any metaprogramming library should have conversion blocks to a more obvious structure, IMAO.
As a standard feature
For a future version of Snap! i can also imagine a debugging switch that will take care of this.
That's okay if you're only ever interested in bugs one level deep! We want access to the entire call stack.
I will refrain from commenting on your speculation about why SPLIT BY BLOCKS behaves the way it does because I don't want to have more than one huge fight with Jens in the forum at a time. (I am being snarky; of course really I don't ever want to fight with Jens. I hate it when that happens!)
Of course I want the entire call stack, too! And I don’t see how my approach wouldn’t support that.
Demo (edit)
—
I’ve already been doing some work on a more user-friendly decomposition.
I’m not sure what your point is. Do you mean that the single-block script being decomposed as a single list (i.e. item 1 is not itself a list) was to be expected, as it can easily be demonstrated? Or rather that it is like I claimed?
What I’ve been trying to convey is that it seems inconsistent to decompose a script of 2 or 3 blocks as a list of (2 or 3) lists, and a script of 1 block as a simple list:
And there’s more, like …what’s the system here?
And how about this gem?
The decomposition rules are unclear to me, I think they should be documented. And, as a next step, rationalized.
On entry to each procedure, you're setting the same global variable to that procedure's info. So the info for whoever called that procedure is gone.
Yes.
I don't see what that example is supposed to prove. The first item is the same as it was before, and the second is irrelevant.
I don't see what's confusing you in these examples, except perhaps the second item of the first item of the result. Everything else is just what I'd expect.
I think probably you aren't accounting for the fact that to Jens commands and reporters are very different from each other. So a stack of command blocks isn't parsed the way a composition of functions is parsed. But I'm just guessing, trying to read your mind, I mean, not Jens's.
You can make a consistent representation
I don’t agree. See the demo in my update to post 35 or so.
In my view on a systematic decomposition process, if you know what happens when you decrease the number of blocks from 4 to 3, you can be sure the same thing happens when you further decrease the number of blocks from 3 to 2 - in this case that’s true - or from 2 to 1 - which is not true in this case, as demonstrated by the first example - or from 1 to 0 - which is not true either, it’s entirely different from anything else again, as demonstrated by the second example. OK, I admit the second example is irrelevant, since an empty ring doesn’t represent “0 instances of a commamd block” - it represents the identity fuction.
Within a decent composition scheme, I would expect a finite number of basic blocks, at least insofar as language primitives are concerned. As follows from my demonstration there’s actually an infinite (albeit countable ) number of “basic”
join
blocks. Don’t you think that’s weird, and impractical?
True.