Skip to Content

BYOB semantics question

« Bugs, Troubleshooting, Suggestions
10 replies [Last post]
anne mulhern
Member

 Hi all,

I've been using BYOB to teach a college level programming course this semester. I focus on using the parts of the language that can be leveraged to do neat things simply. Therefore, dynamic cloning and deletion is attractive. At some point, I showed how you can do just a bit more with dynamic cloning and deletion by using a variable.

In particular, I used examples where sprites are dynamically cloned but the variable they all share is updated in some way, so each of the clones can have distinct behaviors based on one, or at most two, variables.

I have two questions:

1) Why is sending messages so verbose when it is so fundamental in Smalltalk and that fundamentalness should carry over to BYOB ? Btw, I have just said about all I know of Smalltalk in the last sentence so I may be confused. Would it make more sense to have a dedicated message sending block instead of overloading the "of" block in such a way?

2) Why does the "of" block have to be in a launch block instead of a report block?

launch (the script (set age to 3)) of (clone) results in a clone with its age set correctly to 3.

However,

report (the script (set age to 3)) of (clone) results in a clone that still shares its age with its parent.

I think this is a question about semantics. I'm familiar with all sorts of PL semantics, but I'm pretty confused about BYOB semantics.

Thanks for your help.

- mulhern

 

Replies
Jens Mönig
Member

 Hi Anne,

thanks for these thoughtful and "real life" remarks about the issues you encountered teaching OOP with BYOB. It's very exciting for us that you're pressing ahead in pioneering a college level programming course based on BYOB!

I share your concerns in part about overloading the OF block. OTOH instead of sending a textual message which resolves to a method (-name) in the receiver BYOB sends BLOCKS (and scripts). Personally I think that's easier to understand (and to visualize) than having to somehow get a textual handle for blocknames, which would also have to include further (textual) syntax for parameters etc.

However, when a sprite sends "a block" to another sprite, it sometimes doesn't know whether such a block even exists for the receiver. In a textual language such as Smalltalk this doesn't really matter, because a message is after all just a string, and if it doesn't match with one of the receiver's own or inherited methods the receiver just answers #doesNotUnderstand. In a blocks based language the equivalent to a method name is the "block shape" (or block prototype, as we call it), and the equivalent of the method itself is the block's definition body, i.e. the script attached to the prototype's hat block in the block editor. Therefore, in the OF block we're asking the receiving sprite to identify a block "such as this one" indicated by one the sender itself knows about. For future versions of SNAP we're considering a more generic way to describe "block shapes", so that they can be sent to other sprites even if the sender doesn't already have a similar-looking block itself.

Does this all make sense?

Oh, one more thing: This way of having to CALL (or RUN/LAUNCH) a block answered by the receiver certainly isn't self explanatory. That's why - foreseeing this difficulty - we put explicit

   TELL (obj) (action)

   ASK (obj) FOR (reporter)

blocks in our TOOLS sprite. These blocks should be pretty much exactly what you're suggesting, right? We're thinking about always loading them whenever SNAP is launched, but still letting users open a block editor on them so they can demystify message passing for themselves by looking at the - surprisingly simple - implementation code.

Do you think this would help you and your students?

Thanks!

-Jens

anne mulhern
Member

 Thanks Jens.

I appreciate all the hard work on BYOB/Snap!. It's been a very interesting experience teaching with BYOB and I don't think the class would have been nearly as successful in another language. We switched to Python a few weeks ago and students who had been doing well in BYOB spun out when attempting programs of equal difficulty in Python. Wrestling with syntax seems to get in the way of higher level thinking. I would have liked to continue with BYOB further but I was running out of simple and elegant things that I felt I had a thorough understanding of, so I decided I'ld better switch to another language I had strong opinions on the proper use of before I started to flounder ;>

I'll have to spend a little time reflecting on what you've said here before I can give a response.

Will you be at Scratch@MIT this summer? I'ld like to get the chance to talk to you in person and show you the materials I've been working on.

- mulhern

anne mulhern
Member

Text.

Stefano Federici
Member

> Would it make more sense to have a dedicated message sending block instead of overloading the "of" block in such a way?

I think that one of the objectives of brian and jens in creating BYOB was keeping the number of new blocks as small as possible, so to make the Scratch Team seriously take into consideration moving to all the neat things that BYOB makes you available. What exactly are you referring to when you say "sending messages"? Asking another sprite to run one of its local blocks by using the "OF" sensor? Which mechanism would you suggest instead?

> Why does the "of" block have to be in a launch block instead of a report block?

If you click on the "the script (set age to 3)) of (clone)" script, you will see, as a result, a script. So, by inserting this script inside report, you will just pass this script around, you won't execute it in any way. Instead, by using launch or run, you will ask the clone to actually run this script, so the variable will be really set.

 

anne mulhern
Member

> > Would it make more sense to have a dedicated message sending block instead of overloading the "of" block in such a way?

> I think that one of the objectives of brian and jens in creating BYOB was keeping the number of new blocks as small as possible, so to make the Scratch Team seriously take into consideration moving to all the neat things that BYOB makes you available. What exactly are you referring to when you say "sending messages"? Asking another sprite to run one of its local blocks by using the "OF" sensor? Which mechanism would you suggest instead?

They did add a few new blocks, so this might be one more that ought to be added. I don't think I am asking another sprite to run one of its blocks. I'm packing up a little bunch of my code and telling another sprite to run that. I'm not sure what I would suggest, but that "of" block is awkwardly overloaded and counter-intuitive. If it's the one thing that I have to tell my students, "yes, this is how it works, it is wierd, you'll just have to roll with it", then it maybe should be considered to be a candidate for tweeking.

Are you able to address the "It's easy in SmallTalk, why so awkward in Snap!?" question at all.

>> Why does the "of" block have to be in a launch block instead of a report block?

> If you click on the "the script (set age to 3)) of (clone)" script, you will see, as a result, a script. So, by inserting this script inside report, you will just pass this script around, you won't execute it in any way. Instead, by using launch or run, you will ask the clone to actually run this script, so the variable will be really set.

I am well aware that the "the script" block reifies the code inside it, so it is not necessary to explain that to me. I am quite fond of languages with first class functions and pass them around like mad whenever the opportunity arises. But I'm not inserting the script inside the report or launch block. I'm inserting it inside the "of" block. It is the "of" block that may be inserted inside a report or launch block as the case may be. The "of" block itself is not reified.

After some thought, I realize that I have the answer and it's almost obvious. The "of" block is executed, because it's an argument to the launch block. The "of" block evaluates to the value (the script (set age to 3)). During evaluation the major side effect is that a clone is created. The value of the expression, i.e., the script is passed as an argument to the launch block. Somehow, in the process, this value is tagged as applying to the particular sprite that just got cloned, so when the launch block is executed it executes that script for the cloned sprite. This is not a process I really want to be explaining to my students in the fifth week of class, yet message passing itself is alluring.

The ownership of a script is not shown in BYOB in any way. So, if I set the variable f to the result of (the script (set age to 3) of (clone)) and I then click on x to see its value, I see the script, but not the fact that it belongs to the particular sprite that just got cloned.

This still means that "of' is overloaded a little bizarrely, because the code is assigned to the object on the right hand side of the "of'. That is not the usual meaning of "of" and doesn't match up well with the suggested values in the drop down menu, like x-position.

I think I would like a single tell block for message passing. Here is an instance of its use.

tell clone to (the script (set age to 3))

It is not general, but it is nice and simple. I could, of course, write such a thing myself for when I teach my class next year, but then I would have to make sure my class loaded that particular block all the time,which adds overhead.

Brian Harvey
Member

> The ownership of a script is not shown in BYOB in any way. So, if I set the variable f to the result of (the script (set age to 3) of (clone)) and I then click on x to see its value, I see the script, but not the fact that it belongs to the particular sprite that just got cloned.

 

This is an issue we inherit from Scratch, although the difficulties aren't as obtrusive in Scratch.

 

Take the MOVE 10 STEPS block.  To everyone except Jens and John Maloney, this seems to be one universal block.  But in fact that's not how Scratch thinks about it.  Actually each sprite has its own local MOVE 10 STEPS block.  The outward notation would be a better fit to the actual internal mechanism if the block were labelled MOVE SPRITE4 10 STEPS etc.  So, even primitive blocks should really have a mechanism to show which sprite they belong to.

 

As soon as things slow down ("real soon now," as we used to say in the MIT Science Fiction Society) we'll design a serious debugger, which will have the ability to display the owner of any block/script, primitive or user-created.  With OOP it's even a little more complicated since a sprite can inherit (share) a block owned by its parent.

 

Even without thinking about objects, a very similar situation arises when we display the text of a procedure to represent the procedure; that leaves out the defining environment, from which the procedure may get access to local state variables (e.g., for a THE SCRIPT inside a custom block).  You just have to allow that the displayed representation of a value may not include every attribute of that value.  When you evaluate an expression whose value is a sprite (in BYOB 3.1), what you see is a speech balloon containing a picture of the sprite's costume.  You don't see its position, or, more importantly, the values of its local variables.  You need a debugger for that.

 

Stefano Federici
Member

If I correctly understand your suggestion (in which case I completely agree with you) by creating the tell block you would move the "of" to the launch block, that is, instead of

launch ((the script (set age to 3)) of (clone))

you would like something link

launch (the script (set age to 3)) of (clone)

I admit that when you evaluate the of block the reference to the sprite completely disappear. This is not necessary in Scratch (as the result is simpy a value) but if you are able to execute that very result by using a launch/run block, then the reference to the sprite should be somewhere. Currently this is too opaque.

To me your proposal is fine. Even if, for my porposes of "natural" or "spontaneous" programming (that I strongly support), the entire launch block is really too much (and I don't explain it to my students). Indeed, when you think to sprites as real animated entities, you will never have the possibily to impose another sprite to do something. The correct mechanism, at least in my theoretical programming environment, would be sending the sprite a message (hopefully with parameters). If the sprite is willing to accept that request it will be equipped by a suitable "receive" block.

This is what I would strongly support. Instead, Brian and Jens, that support more powerful and flexible programming languages, immediately refused my view. My goal is the same of yours: if you make it easier to understand (and to me what is closer to the real world is easier) students will learn it sooner and use it better.

Brian Harvey
Member

I'll take the blame for this one.  My sense of what's elegant doesn't always match that of normal people. :-/

 

It's exactly right that we were trying to minimize the number of new blocks in the (hopeless) quest to convince the Scratch Team to incorporate our ideas in Scratch 2.0.  And, if you think about just the original Scratch OF block, what it's doing is precisely message passing.  "X position" is a message (a text string), and "Sprite2" is [the name of, since they're not first class in Scratch] an object.

 

So it seemed most elegant to me, since we were already handed a message passing block, to use that block for all message passing.

 

We added the TELL and ASK blocks to the tool sprite because we quickly learned that other people didn't find the generalized OF as elegant as I still do. :-(  If we provide TELL and ASK on startup, will you mind that they're implemented using OF?  You don't have to teach it to your students.

 

About RUN/LAUNCH vs. CALL, this issue has nothing to do with OOP.  We inherit from Scratch the fact that some blocks report a value, while others don't.  The former are oval or hexagonal; the latter are jigsaw-shaped.  This is why we have THE BLOCK and THE SCRIPT instead of a single lambda, and it's why, correspondingly, you CALL a reporter block but you RUN a script (which might be a single command block).  LAUNCH is just a variant of RUN that starts a new thread, like BROADCAST vs. BROADCAST AND WAIT respectively.  It's convenient to use LAUNCH with message-passing, but you can LAUNCH a new thread within a single sprite.

 

About BYOB vs. Smalltalk, what I think is that part of the genius of Scratch was to finesse the distinction between a procedure and its name -- to a kid, "the MOVE 10 STEPS block" and "the 'MOVE 10 STEPS' block" mean the same thing.  If you view a message as being the name of a method, this means that in Scratch it's really hard to make a distinction between message and method.  A block is its own name.  Almost all the time, in Scratch, this unproblematically lets kids get on with writing programs without having to think at all about the language semantics.  But in BYOB it sometimes makes it harder to express oneself precisely.  Jens, did I get this right?

 

I note in passing that some Scratch block names are quite long, and you'd get tired of typing "GLIDE _ SECS TO X: _ Y: _" as a message after a while.  Using the reified block as its own message /is/ terse and simple, looked at from the right angle. :-)

 

We are about to rethink all this for Snap! because we want to generalize the OOP system to include other kinds of objects, e.g., costumes and sounds.  If we keep the same message passing approach, we'll be overloading the second input of OF as well as the first. Nothing is settled yet.  But we'll certainly provide ASK and TELL (we need both for the same reason as CALL and RUN) on startup.

 

anne mulhern
Member

Have you then decided to give up on the hopeless quest and make use of the freedom that provides?

Brian Harvey
Member

A qualified yes.  For one thing, we're going to split up the old tool sprite into modules, and one of those subsets will be preloaded when you start Snap!.  So you'll have TELL and ASK (one command, one reporter, sorry) but they'll still be implemented with OF, the basic message passing block.  Another example is that people keep wanting support for various neat hardware accessories, from NXT to Arduino to Knect.  But I don't want to have to keep adding half a dozen primitive blocks whenever a new toy is invented; instead, I want to work out how to design primitive blocks read-from-USB and send-to-USB in terms of which people can write libraries for each device.  We'll probably (although this isn't settled and there are competing design ideas) split CALL WITH INPUTS and CALL WITH INPUT LIST into two blocks instead of squeezing them into one block with a pulldown.  So, yes, you'll see a modest increase in the number of primitives, but you won't see exponential growth.

 

PS:  IANJ, but I'll be at Scratch@MIT and would love to get together about curriculum!