Script builder library (Part 1)

A library that can be used for building scripts within scripts, if you want to do that.


wow, that's a really great library. It would come in handy sometime. I wish this would be put into snap (as a library, not primitive)

haha lol

1 Like

Wow, cool hack!

1 Like

how did u learn JS
How did u learn about blockMorph and other Morph, Is there any tutorial about Morph?

I learned JavaScript online.

And no, I did not find a tutorial on Snap! morphs. I don't even think there are any tutorials. I only figured out how to do the stuff here by printing blocks and other stuff to the console and inspecting their properties, and by looking at some of the source code.

That’s big brain, Why there’s no tutorials then

I learned a lot of Morphic by just reading the docs and looking at examples, I might read the whole morphic code sometime

At the beginning of morphic.js is a huge comment with a lot of documentation about Morphic. There isn't a tutorial, in the sense of a step-by-step guide to learning, but you can certainly learn stuff by reading it.

We don't put a huge effort into Morphic documentation because, honestly, the Snap! documentation isn't in such great shape and that comes first. We have the Reference Manual, which I'm proud of, but it's also not a tutorial. The help screens need work, too.

You lot are very into modifying Snap!, which is cool, but that's not where most of our users are.

Isn't Morphic.js a JavaScript implementation of the original Morphic in Squeak? Could you just learn the concepts like Morphs through a Squeak Morphic tutorial and apply that to Morphic.js?

This is very, very, very amazing!

Are you up for a lot more work on this? It's the beginning of what I need to make macros. But...

It's too narrowly focused on scripts, as opposed to expressions. It needs, for example, a reporter SLOT (n) OF (expr) to be able to explore the insides of an expression.

I want to be able to ask questions about what a script or an expression does. The first step is a reporter that reports the block spec of a block; with that we can work out a more user-friendly representation maybe.

There should be a way to extract the script from a custom block, and preferably also the enclosing environment if any.

And, I don't know if this can be done in a library, but I need a way to define a new custom block programmatically, given a block spec and a script I guess.

Then comes the hard part: When a macro reports a script or expression, it should be run or called in place of the macro call, i.e., in the environment of the caller of the macro. I bet this can be faked with call/cc, actually, now I think of it; just arrange to do a call/cc around the macro, and call the saved continuation with the macro's result. But the call/cc has to happen in the caller, not in the macro.

Anyway, are you up for this? If so we can iron out the details. It would make me very happy not to have to do this myself...


Sigh. All of this already exists inside Snap, how else would it work internally? Of course we can programmatically deconstruct & analyze blocks and scripts, and of course we can programmatically generate and manipulate blocks, inputs, scripts, whatever, and execute them in whichever context we choose: It's our system. There is hardly any code to write for that, only design to be agreed upon.

Well, yes, sure. But it hasn't been made visible to Snap! programmers. And afaik it's never been done programmatically, only in response to users dropping blocks on or below other blocks. What you're saying is the reason why if you look inside these blocks there isn't that much code. That and the fact that gray rings already give us scripts and expressions as data.

I was about to say that I don't think the design, at this level of abstraction, is so important; I see these blocks as the tools I'd want to use to build the real interface. But I guess you're right, this does raise a design issue, now that I think about it, and here it is:

These blocks sort of recapitulate the list blocks. That raises the question of whether it would be better to just use the list blocks, the same as you do for pixels, even though internally a bitmap isn't a Snap! list. That would be nice, I guess; it might avoid the need to convert explicitly between scripts and ASTs. And yeah, that argues against trying to implement macros as a library.

(But, here's an argument the other way: There are a bazillion details I don't yet understand -- haven't yet thought of, more like -- and having a macro library with a user-visible layer built on top of these blocks would allow design experimentation more easily than having to build variants of Snap!. Then when we pick the winning design you'd be more than welcome to reimplement it as primitive.)

It's late at night so I'm not 100% sure I'm making sense. But I think I am.

My target is to be able to build the examples from the program as data chapter and the macros chapter of CSLS.

One deep subtlety that I have to understand better is that a Logo procedure, because of dynamic scope, is nothing but its text, but the Snap! equivalent of TEXT is going to have to also provide the environment -- the actual environment, so mutating it will be visible to users of the procedure (or maybe there will be a separate ENVIRONMENT selector for procedures. Or maybe I'm confusing the case of custom blocks with the case of lambda expressions created inside a procedure. I'll figure this out when I wake up.

But I still say this is an amazing piece of work! And I still want to benefit from it...

1 Like

Sure. Is there such a tutorial?

Sure, maybe I could help you with that. Though I am not very familiar with macros since I have never used them, or attempted to learn about them before now. I think they serve almost the same purpose as functions?

can u make some tutorials?please,please,please!

that's crazy


A macro is a reporter that reports a chunk of code (this is why your work is interesting) which is then evaluated in the caller in place of the macro call. This doesn't matter if the code just computes some function. Macros are needed when you want to change the flow of control of the caller, or declare script variables in the caller.

So, for example, Snap! ordinarily initializes new variables with the value 0. Let's say I want to make a bunch of local variables and initialize them all to empty lists. I write this block:
reshape script pic
(using blocks from the Create Variables library). My idea is to call it from other blocks, like this:
reshape script pic (1)
But it doesn't work! Why not? Because a, b, and c are declared as script variables of the block SCRIPT LIST VARIABLES, not of the block FOO.

So instead I have to make SCRIPT LIST VARIABLES a macro (we don't have a notation for that yet) that does this:

(I've made this a reporter because all macros are reporters, but really I want the hat block to say that it's a command macro, because what it reports is a script, rather than an expression.) Now, when FOO calls SCRIPT LIST VARIABLES, the script in the gray ring will be evaluated inside FOO, right where the macro call is. In effect the macro call is replaced by whatever the macro reports. So now the script variables are declared inside FOO, not inside SCRIPT LIST VARIABLES.

Does that make sense? If not, try to ask a question that helps me see where you're lost.

EDIT: Oh, whoops, if you're lost it's my fault, because I neglected to mention that the variable VARS is local to SCRIPT LIST VARIABLES, so it's not obvious why I can use it in the code that the macro reports, which will be evaluated in a different procedure that doesn't have a variable VARS. The answer is that the gray ring doesn't just encapsulate the code; it also remembers the environment in which it's made, in this case the environment of SCRIPT LIST VARIABLES, which includes its input variable VARS.

1 Like