How do I implement a simple JavaScript function in Snap!

WARNING! this topic contains:

  • strong opinions, sarcasm, rants (PG-13)
  • JavaScript (R) :smirk:

ā€”ā€”ā€”

I'm trying to understand how I can implement JavaScript code as part of a Snap! function.
Used Blockly as an input device, wrote a really simple function, tried to make the code fit into the Programming tools SANDBOX script pic (28) block.
I failed ... can anyone tell me what seems to be the cause?

Programming tools SANDBOX script pic (32)

Thanks in advance!

Snap lists aren't JavaScript arrays. If you want to access Snap's data types in JS you'll need to dig into their implementation code, which is all open, but which I don't encourage as a topic on this forum.

I know this keeps coming up a lot and folks hate me for discouraging JS discussions, but hear me out: This forum is stuffed to the brim with (males) people who love Snap so much they want to hack it in the "underlying" programming language in search for ground-level truth, believing that learning how to hack Snap will make them competent JS programmers. Both motivations are problematic: If JS implementation discussions tend to spring up in the "advanced" topics discussions beginner-level learners will jump to the conclusion that learning JS somehow fast-tracks their understanding of Snap (which it doesn't). Worse, kids are going to feel peer pressure to fiddle around with mostly boring code snippets just because they get the impression that that's what the hotshots do here, and that that's something that gets then the respect of the hotshots here. And then they'll develop naive notions of how "JS" works, because they've read some code elsewhere on Stackoverflow or in Blockly that worked, but they don't realize that that wasn't "the JavaScript programming language (TM)" but some parts of a library.

In your example: "data" is a Snap list object, not an array. Snap lists have a method named length, not a property. But because this is JavaScript, every method is also a property. Therefore, if you check whether the property (!) length is true-ish (another problematic concept in JS, just sayin'), you believe that the result tells you whether the list has zero (false) or more (true) elements. But, since data is a Snap list it only tells you whether that objects has a property named length whose value is not null and not undefined. Since there is a method named length the result is always true. In order to get what you think you're getting you'd have to call length() instead. However, you're making it even worse by assigning the method (!) named "length" to the variable named "i_end" and by using that inside both a conditional and a for-loop, mistakingly assuming it's a number when it really is a function.

See, this is hard, and you didn't even learn anything, at least nothing that's even remotely interesting, or anything that will make you a better programmer. This is exactly why I strongly discourage such discussions about JS and Snap here. I know folks lap it up. They're overly eager to learn the "secrets" behind Snap. And I'm not keeping any secrets closed, by golly, it's all open. But one reason we're having it all open for everybody to see is that we don't have to talk about it here.

Now, since you're an aspiring JS programmer you've learned that slice() copies an array. But you didn't realize that a list isn't an array and does not have a method named slice, same story. Is this really a topic that's interesting in this forum? Do you think kids - or teachers - learn something worthwhile from such a question?

It gets even worse - and way more difficult - if you want to write JavaScript functions that work on larger data sets, and that require to play ball with other scripts running simultaneously, because JavaScript doesn't support that.

Long story short, I hope you understand my point about not encouraging - and even actively discouraging - JavaScript questions and discussion here. We made Snap! so we can teach powerful ideas of programming. We did not make it so we get sucked down to haggling with the trivialities of text-based programming languages.

First of all: thank you for replying.

Speaking only for myself: indeed I'm enthusiastic about block-based languages, especially Snap ! , and actually not interested in JavaScript for its own good. However, even though Snap ! has great HOF's, sometimes they don't fit as a solution to a problem (or puzzle, if you like).

Example
I recently wanted to convert a series of intervals to a cumulative series; the formula is something like: cumulative [i] = cumulative [i-1] + interval [i].
I couldn't figure out how to code this (in an even remotely runtime-efficient way) using standard Snap ! HOF's (like MAP, COMBINE) - I'm not saying it's not possible, perhaps it is. Anyway, I coded it using a FOR EACH-loop (which happens to be a HOF too :smirk: ):

Programming tools SANDBOX script pic (34)

It struck me that, with a large data list, this function ran over a thousand times slower than COMBINE, which does something similar (but different). I was curious if I could fix this by writing a few lines of JavaScript code (using the Blockly converter, 'cause I'm no JS expert, nor do I aspire to become one). I looked up the Programming tools SANDBOX script pic (35) block's HELP-text and thought more or less understood how to do get it done. After several failed attempts I tried an even simpler function, as refered to in my original post, and failed again. Since, like you mentioned, many Snap ! enthusiasts apparently have some JavaScript integration experience, I was hoping one of them could provide me with a few practical hints.

If we can agree that implementing JavaScript code snippets within Snap ! is supported by the IDE, and that indeed it is an advanced subject, I don't see where else to post a request for help but in the "Advanced Help with Snap!" section of the forum. I do hear what you're saying about beginner-level learners, though I'm not sure if (even unintentionally) inspiring them to look into JavaScript (or any other programming language) is necessarily a bad thing. If you believe it is, perhaps you need to discuss the structure of the forum with your team, or even altogether removing the JavaScript-option from Snap !.

Actually, I created a list in Blockly; Blockly converted it to JavaScript code (as you can see from the handling of "i_inc"). That's exactly why I tried Blockly: to circumvent the intracies of JavaScript.

I did: apparently it's not as simple as it looked - pity.

Mostly I agree with everything you said, but not this part. You could say the same thing about Snap! code! Users post questions, including what we think are trivial questions, about their Snap! programs. "How do I exchange the rows and columns of a matrix?"

We should consider prepending a warning for new users at the head of every Advanced Topics thread.

This sort of inductive definition isn't well suited to MAP, which makes no promises about the order in which it computes the items of its result. Technically you can't use COMBINE either because it doesn't promise to fold left to right or right to left.

We are a teaching language, so we designed our HOFs to be as simple as possible. Lisp has FOLDL and FOLDR, which do make promises about the order of evaluation. The cost of our design is that, as you say, you can't do everything with HOFs alone, but that's just as well, since we want to teach recursion too. ;~)

The absolutely most elegant possible way to write your program is to load the streams library and do this:

but in fact I'd be inclined to write it recursively.

P.S. FOR EACH is a higher order procedure, but it's not a higher order function because it's not a function at all!

I added one.

ā€¦ in which case both HELP-texts need to be revised: they present examples implying evaluation from the head onwards. The same applies to FOR EACH (btw: an HOP, indeed).

Solution with streams
Utilizing the stream mechanism is always elegant, I agree. The fact that your proposed solution is almost correct, and thus must have been written without testing, only proves your genius :wink: .

Below is a correct version, embedded in a test script:

Recursion will work fine as well, Iā€™m sure.

Faster version?
Iā€™m (also) still open for advice as for how to construct a really fast version, perhaps with JavaScript :smirk: .

"warp" is your friend :wink:

untitled script pic - 2023-04-20T032132.231

untitled script pic - 2023-04-20T032135.343

No, you're misunderstanding what I said. We do promise that the order of items in the result matches the order of items in the input. We just don't promise which item is computed first. It's a question of time, not position.

FOR EACH is different. It does promise to process the list left to right. The idea is that in functional programming you don't care when things happen, because no part of the computation depends on any other part of the computation. FOR EACH isn't functional; it's sequential.

Oh, no, what it proves is that when you said "interval" I read that as, e.g., "between 5 and 8," represented as the list {5.8}.

I know this keeps coming up a lot and folks hate me for discouraging JS discussions, but hear me out: This forum is stuffed to the brim with (males) people who love Snap so much they want to hack it in the "underlying" programming language in search for ground-level truth, believing that learning how to hack Snap will make them competent JS programmers.

I'm not male, I want to get into the weeds with snap because as far as I'm concerned, there is a widening gulf between "human readable" and "human understandable" and as you point out, coders who are usually men adapt to the rules of programming languages, whereas women try to ask why they can't just DO something and I think there is a middle ground.

My issue is that I can read snap code easily, but when I hit "new project" the interpreter sits empty until I close it because "I can do anything... sure where do I start... uhhh..."

I also think that locking everything into browsers is a mistake, but it does make sense for a teaching language to have those locks in place.

I would like to eventually extend snap until it breaks so I can then rewrite it into my own language that does what I want. Because I don't think like a programmer and because of that, I can't really do anything advanced because increasingly tech is becoming "Don't worry about that, someone somewhere else knows the answer" and I really, really, really, REALLY don't like it.

related but unrelated, is there any news on the snap3 course on sap? Or have I missed it because I don't know where to look?

BYOB was a separate program you installed on your computer. That was great for independent learners but not great for teachers, because their school's IT czar wouldn't let them install software that didn't come from Microsoft or Adobe. So for Snap! we went browser-based, but now the IT people have learned to whitelist only sites that come from Google or, these days, Scratch. You can't win.

If that's the problem you're trying to solve, I don't see how moving to a language you can't even read will help!

Here are some ways to get project ideas:

  • Look at other people's projects on the community site.

  • In our Beauty and Joy of Computing curriculum (bjc.edc.org) each unit has an "optional projects" section with ideas you can browse.

  • Build a non-video game, such as Wordle or Sudoku or Mastermind. I suggest those rather than video games because you don't get caught up in details of timing or multiprocessing, but can focus on the logic.

  • Make an animation. It doesn't have to be very complicated; one of my favorites is a ferris wheel.

Does that help?

BYOB was a separate program you installed on your computer

Yeah, I've been following snap for a long time. I'm aware of that stuff and even agree on that logic.
What I'm after is a downloadable and native snap, now keeping in mind, I'm also aware that my goals and yours absolutely diverge, so I would happily do it myself ... In Theory.

Now as to not understanding, I suppose I can read code just fine. I'm a little (Lot) self deprecating, the issue lies in that I'm a visual person and snap opens up a window that I've been wanting open for a while, whereas text, for me is an encyclopedia entry about how the sausage is made, but does not show me how the sausage is made.
Whereas I click the code in snap and the turtle updates, and if I've got stepping mode on, it shows me what it's doing and I have a visual tool that can and shows me what it's doing and what it's referencing? Yeah. That'd get past my stubborn brain. All the way through. Fast.

I can't however drag and drop r_draw.c into snap because snap does not understand it. Whereas if I ever got past my brain block, that's what I'd do, but not just c or cpp, but any language type, cause the language doesn't matter. What the machine does is the key.

Also from a modern computing standpoint, drag and dropping blocks in an AR environment with my hands makes far, far, far, FAR more sense than insisting a keyboard/mouse is the pinnacle of tech. Don't get me wrong, I'm using an expensive logitech keyboard/mouse set and they are very nice, but beyond RGB lighting, what's the difference between this and an old 1985 Model M IBM keyboard... and the answer is honestly? Very little. Same with the mouse, it's wireless at an insane dpi sensitivity, but really? Aside from the RGB lighting and button count? Same thing.

Tech's been in a "the same thing but SHINY" loop for as long as I remember, and it's achieved a lot, but a lot less than it should have in my long winded opinion.

Two things about that.

First, it's an unreasonable expectation. You can't import a .c file into a Python program or a Javascript program either; each programming language is different from the others.

Second, drawing in C isn't any more "how the sausage is made" than drawing in Snap!. People keep wanting to see "the real code" in a Snap! project, as if Snap! were a GUI layered on top of a "real" language, but it's not. We're just as "real" as any other programming language! When you use a drawing library in C you're sitting on top of an abstraction, same as in Snap!. Abstraction is what makes it possible to write the program you want to write, instead of (for example) having to draw a line pixel by pixel.

If you insist on a pixel-by-pixel view, the place to look is in your browser's implementation of HTML Canvas.

I have strong feelings about keyboards, namely, the only good one is the original Microsoft Natural Ergonomic Keyboard 4000, the only good thing Microsoft ever did, so naturally they don't make them any more (but you can still buy one with a little research online). They split the key layout so that each hand can be at its natural angle, but the thing that makes this keyboard unique in the world, as far as I've been able to tell, is that they let you raise the front of the keyboard, so your wrist can bend down a little, which is what it wants to do, instead of having to bend backwards as with any other keyboard. The other keyboards raise the back of the keyboard (which this one also allows), which is just stupid.

I know that the entire world can't really be stupid in the same way, so they must have some idea in mind that I'm missing. All I know is that my wrists love this keyboard, and I won't use any other.

</rant>

@dardoro: thanks for the DURATION block, I think it's really easy to use when measuring and comparing execution speed !

The proposed faster solution for CUMULATIVE function will only work when MAP is evaluated in one direction (from ITEM (1) up), see post #4. Thanks for the hint, anyway.

You're right, of course. It's a subtle yet important difference. I hadn't thought of it that way yet.

cumulative script pic (4)

cumulative script pic (1)

cumulative script pic (2)

cumulative script pic (5)

Second, drawing in C isn't any more "how the sausage is made" than drawing in Snap*!*

R_Draw.c is for example, how Quake draws between each refresh. I'm not after the "real code" of snap! at all, I just want to open a .c file in a block editor. Something along the lines of notepad++ and/or programmers notepad or pick editor of choice using the language of choice.

Once I've I've loaded quake into snap and then snap into quake, then I'll try something else, probably something like a demotool like werkkzeug, which uses C++. It's about seeing the code work instead of guessing how the code works, because no matter which text language I look at. It flies all the way over head.

I have no strong inclination between c, c++, python or snap! but I'd much rather use blocks regardless of language. Snap! is not my end goal, but it is the tool I like the most that I want to use to build towards my own end goal. Am I trying too much with the wrong intent? The probability is very close to 1, but I want to try anyway, because if I'm wrong or even in the unlikely circumstance that I'm right, I learned it my way. Stubborn? YUP. That's meeeeee :slight_smile:

I have the same issue with writing. I can write the story fine, but then I ask myself what billboard is 50m to the left of the character as she crosses the street and I then sit in my chair picturing the entire scene instead of writing "The character crossed the street when the light went green"

Iā€™m afraid @dardoro ā€™s JavaScript implementation is unbeatable.
However I did find a non-JS algorithm that outperforms any other (so far) in Snap ! :

The algorithm takes the original list and adds the same list but with "0" inserted at item 1:

x1 x2 x3 x4 x5 x6 x7 x8 ...
(0) x1 x2 x3 x4 x5 x6 x7 x8 ...
------------------------------------ +
y1 y2 y3 y4 y5 y6 y7 y8 y9 ...

Then it takes this new list and adds the same list but with 2 "0"-s inserted at item 1.

y1 y2 y3 y4 y5 y6 y7 y8 y9 ...
(0)(0) y1 y2 y3 y4 y5 y6 y7 y8 y9 ā€¦
---------------------------------------- +
z1 z2 z3 z4 z5 z6 z7 z8 z9 z10 ...

and this is equivalent to:

x1 x2 x3 x4 x5 x6 x7 x8 ...
(0) x1 x2 x3 x4 x5 x6 x7 x8 ...
(0)(0) x1 x2 x3 x4 x5 x6 x7 x8 ...
(0)(0)(0) x1 x2 x3 x4 x5 x6 x7 x8 ...
---------------------------------------- +
z1 z2 z3 z4 z5 z6 z7 z8 z9 z10 ...

Next it takes the newest list and adds the same list but with 4 "0"-s inserted at item 1ā€¦ and so on until 2^n versions of the original list have been added, each shifted to the right by one more position. 2^n must be at least as large as the length of the original list, and the sum is finished.

That gave me a smile. But you can put that characteristic to work; Real Writers become known as Real Writers because they include that sort of detail, and make it relevant by describing the character's reaction to the billboard. Go read the first several pages of any chapter of Tolkien.

By all means, do it your way! It's my job to suggest alternatives, but it's not my job to hit you over the head with them.

But you're not going to get the ability to drag C code into Snap! blocks. That would be a huge distraction from our own purposes; I think maybe you underestimate how hard it'd be to implement. We can do it with Javascript because that's what the browser provides; in that sense it really is how the sausage is made.

Look into Blockly. They see their job as more like what you want, being a GUI around some "real" language. Maybe someone has used it with C.

But know that Snap! is a "real" language. That's why we're not Scratch, whose goal is to be a simple language. Because of hyperblocks, we're a more expressive language than most of those grownup ones.

That gave me a smile. But you can put that characteristic to work; Real Writers become known as Real Writers because they include that sort of detail, and make it relevant by describing the character's reaction to the billboard. Go read the first several pages of any chapter of Tolkien.

Yup. World building is very much a thing, but translating the world in my brain to the world on the screen is the problem. Always has been. Whether it's writing, drawing, programming. I get stuck because the canvas I want is not the canvas available.

But you're not going to get the ability to drag C code into Snap*!* blocks. That would be a huge distraction from our own purposes; I think maybe you underestimate how hard it'd be to implement. We can do it with Javascript because that's what the browser provides; in that sense it really is how the sausage is made.

Sure, but that's my point. I know that. I've been saying that what I want diverges from what you want, which is why I want to do it myself... somehow. If I ever get past my defective brain I'll do it.

Snap is absolutely a real language, you have no disagreement from me on that statement. Absolutely none. It's incredible work :slight_smile:

Thank you!