Can't broadcast to all in run block

Here's a bug I ran into a while ago, that is still in snap (I just never got around to posting it).

Running a broadcast block in a ring, with an input puts the input in the sprite input in the broadcast block, when it's hidden, broadcasting the message to the sprite with the same name as the message.

for example, this script

untitled script pic

will broadcast "test" to a sprite called "test", even though the broadcast block is not expanded.

And it doesn't help that this still broadcasts to the sprite called "test" with the (new) data of "all"
untitled script pic (85)

And this just throws an error
image

It's treating the message and the reciever as 1 input. This is very bad design.
Here's an example project
https://snap.berkeley.edu/snap/snap.html#present:Username=ego-lay_atman-bay&ProjectName=broadcast%20bug

The second and third examples are just what you'd expect, given the first one. That is, if you expanded the BROADCAST block so that the message input and the sprite input are both visible, all three examples follow the substitution rules: the number of actual arguments must match the number of input slots, except that one actual argument will match any number of input slots.

So the issue you're raising is that hidden input slots still count as input slots. For variadic inputs, it's the number of visible input slots that counts, and from a user perspective, hidden input slots like the ones in BROADCAST are just a special case of variadic inputs with 0/0/1 arity, and so I agree, RUN/CALL shouldn't fill the hidden slots.

That's not a bug and those aren't "hidden inputs slots". broadcast has 2 inputs: a message and a second variadic input that lets you specify the receiver and an optional data payload.

I don't understand. It sounds like I upset you by using the word "hidden." I just mean that the variadic input might have no slots exposed, just like untitled script pic, and when you CALL it, we don't substitute an actual argument value into the unseen slots:

So when I say


I expect the message "foo" to be sent to every sprite. But that's not what happens; "foo" also goes into the invisible receiver input slot.

That's what I'd expect to happen if I'd said


(although that would be a weird thing to do; if the user goes to the trouble of making that second slot empty (instead of the default ALL), I'd expect a second actual input value to be in the RUN, because it doesn't really make much sense to send a sprite its own name as a message.)

And indeed if I say


the sprite goes to (100, 100).

But


doesn't report "foofoo".

Actually, further experiments show that JOIN with no input slots visible doesn't behave like LIST with no input slots visible:



versus the LIST picture above, and this one:

P.S. If I were a user, I would describe BROADCAST as having one required and two optional inputs. If you twisted my arm, I'd let you say it has one variadic input with all three slots. Yes, I know, if I carefully look at where the arrowheads appear, there isn't a left arrowhead to hide the first input slot, but I think the model you want users to have is unlikely to be the model they do have. (But even with your model I don't understand the behavior of RUN [BROADCAST].)

Just returning to the broadcast block issue ...

I think I understand the logic of most behaviours (given the "hidden" slots)

But I don't understand why Sprite doesn't respond to this broadcast (whereas test sprite does)

The workaround is easy but I'd like to know why the other one doesn't behave in the same manner

image

Oh. I misread this the first time. I don't know why it behaves that way.

I've also discovered another weird thing. I tried doing it the old-fashion way of sending a message to a sprite, using a list, and got this.


And I can confirm that the second input in the run block, is indeed data

broadcast bug script pic (1)

I actually went back to 6.9.2, and none of this happened. The broadcast list worked as, sending the message "test" to the sprite named "Sprite", and running it would work the same way.
untitled script pic (86)


untitled script pic (87)

oh, and sticking the list directly into the message input is different in 6.0 and 8.0(/7.0?)

broadcast bug script pic (2)

8.0

6.0

repeat after me: broadcast has 2 inputs:

You know, Jens, I don't think I'm the absolutely stupidest or most ignorant of users, and if I don't understand something, the odds are other people also won't understand it, and instead of getting mad at me and being sarcastic, maybe we could think together about how to make the behavior easier to understand.

My mental model of how variadic inputs work with RUN or CALL is this:




Somewhat to my dismay, JOIN almost does the same thing, but not quite:

*

A custom block with a variadic input seems to behave like JOIN, alas:

*



So given the anomalous behavior of a variadic input with no slots showing, I guess I can finally see why you think BROADCAST is doing the right thing. It's substituting the one actual input into the first (unproblematic) visible slot, then for the variadic input with no visible slots it substitutes once.

But, aside from the wrong behavior about zero-slot variadic inputs altogether, the "to" slot in BROADCAST has a default value and so shouldn't be substituted into even if visible, like this:

And finally, we have this argument all the time, you think users should think in terms of how you implemented whatever we're arguing about, whereas I think that if you ask 100 Snap! users how many inputs
untitled script pic (15)
has, all 100 of them will say three, not two, and the behavior should follow what users expect, or else you have to change the appearance of that block so that it looks like it has two inputs.

The user expectation will be especially strong since the three slots have three different semantics! Variadic inputs are generally semantically uniform.

If it does, then why does this not broadcast to all sprites?

untitled script pic (85)

I clearly put "all" in the second input, meaning, it should broadcast to all sprites. It instead, broadcasts to the sprite named "test", which is the first input, the message.

Even this doesn't make sense

And if you're thinking it's just that I'm adding an input that isn't there,

This doesn't follow your "broadcast has 2 inputs" because it seems like 1 input that is being treated as 2.

He means two input slots, not two actual input expressions.

No, wait, I didn't do enough experiments. A variadic input with no visible slots will take any number of inputs:


which is a useful feature. I guess LIST should do that too! (This would also solve my problem with variadic inputs in backquote, because I could just always make a zero-slot version of the block.)

But I don't understand the behavior with more slots:

?



I guess I understand all but the one-slot response. I would have expected an error message like the ones for two and four slots. An empty return value is just weird.

In Snap! an empty slot serves as an implicit parameter. A collapsed "multiple inputs" type slot is an empty variadic slot, i.e. it can be called with any number ("arity") of parameters:

variadic

Expanding a "multiple inputs" type slot makes it no longer empty, but filled with (list) data. Now there is a special ("abnormal") rule of treating empty (sub-) slots inside the multi-slot as implicit parameters of the block, which you designed and specified (against my objections at the time, because I wanted to use list-type inputs and list reporters for everything), making the block not longer "variadic" but polyadic, i.e. it has to be called with a number of inputs that matches the empty (sub-) slots:

Some polyadic inputs inside primitives cannot be collapsed into behaving as variadic ones, among those are list, call etc. This is really basic Snap! semantics for over a decade, and we used to be very clear on them, with you making arguments for them instead of against them. Until a kid comes along and is confused, when you start attacking the implementation I didn't want to begin with. This is when I get mad.

This is the part I guess I've never understood. I think it's only recently that you introduced the term "polyadic" and it's only just now that I got a clear sense of the difference.

Could you please explain why LIST shouldn't behave just like JOIN with respect to input slots? And I guess clarify what the issue is with CALL? You don't mean only that the text "with inputs" appears when you make actual argument slots, right?

And can you explain this example:

(Forum misfeature: when you drag a picture from an earlier message into the one you're drafting, it doesn't copy the scale factor and doesn't let you set it either. :~(    )

I slightly remember now having to argue for the special case that a variadic input with no slots shown should accept any number of actual arguments. For what it's worth, I still stand by letting users build blocks with variadic inputs, and apart from the picture above I still stand by how they behave with CALL/RUN. (The decades-old decision I wish we could change is that all blocks should be the same shape, ovals with tabs, so that the same blocks can either be stacked vertically or nested, but never mind that now.)

Well, I stand by thinking it matters if users are confused, especially experienced users. And in the specific case of BROADCAST, although it took me a while to understand how you were thinking about it, there is a non-decades-old, new piece of semantics, namely you thinking of the sprite target and the data load as two pieces of a single {vari,poly}adic input. I'm pretty sure we've never had a variadic input whose two slots mean two different things.

(P.S. If an experienced kid is confused about something, it's a good bet that every teacher will be confused about it, if they happen to think about it!)

You've convinced me that a "collapsed" BROADCAST block should look like
untitled script pic
and furthermore that we should be able to add a hovertext to each arrowhead. And also that users need to be able to specify min/default/max arity for their variadic inputs. Maybe it's only 0/0/1 inputs that need a hovertext over the arrowhead; I'm not sure.

But I am sure that BROADCAST has three separate inputs, with three different semantics, two of them optional.

That's why I select the image, then click quote.

I actually have to agree with that. That would make this issue be gone, or at least make sense.

But, as I keep saying, the underlying issue here, is that the message is being passed as the reciever, and adding a new input just adds data, not allowing the user to specify the sprite to broadcast to.

yes, I've recently begun to use "polyadic" as a synonym for slots of type "multiple inputs", because in most of the cases they aren't "variadic" at all, only when you collapse them.

Some multi-slots such as in list and call are explicitly barred from participating in the implicit-parameter-when-collapsed semantics so they can be used as truly empty slots inside rings, e.g. when comparing the value of a variable to an empty list literal, or so we can write recursive calls inside a ring using call or run. I hate to say it, but it is obvious when you think about it, and it has been that way from the very beginning. :slight_smile:

Arity mismatches inside multi-input slots do not throw an error but report "nothing".

Having explained non-implicit-empty-poly slots just now made me realize that we'll make the broadcast block's second input slot just that in the next patch (in September). That'll solve the current confusion.

Yes, it will. But actually I still think that two arrowheads with hovertexts is the right thing. It would allow expanding the data one without expanding the target one. And it avoids establishing the (imho) pernicious precedent that a xxxadic input can have slots with unrelated meanings. Actually I have to admit there's something a little like that in the Colors and Crayons library, but only for lack of the min/default/max feature and the hovertext feature.

C'mon, Jens, you're not just insulting me, but also the users. I have only just now realized why this doesn't work:


untitled script pic (1)
(Never mind that you don't need the CALL in this simple case. I'm pretty sure I remember a user having this very problem of wanting to use a zero-slot JOIN to denote the empty string—precisely because an empty slot would have been substituted into—in a situation that did require a CALL.)

You're going to hate this idea, but I think zero-slot variadic inputs should "absorb" actual input values only if there are no visible slots in the entire expression. Maybe even limit it to cases where the block with the zero-slot variadic input is the entire expression. You'll hate it because it's a special case on top of a special case, but I think the resulting behavior would much better fit users' expectations, because in non-zero-slot situations we've taught them to count input slots with respect to the entire expression, not with respect to individual blocks within the expression. That entire-expression count should apply to zero-slot counts too. And yes, I agree that this is my fault for not thinking through all of the implications of the design. And I think I finally understand what Dan Ingalls meant (in that recorded lecture I used to play in 61A) by a syntax being "not well-founded."

By the way, one reason I find your polyadic/variadic distinction confusing is that in my mind "variadic" is a property of an input in the procedure's definition (a formal parameter), rather than of a slot in a particular calling expression. That's one reason I've not been understanding some of the explanations you consider obvious, e.g.,

This is meaningless if it's the formal parameter that's variadic. We should work out a vocabulary that lets us talk unambiguously about either context.

Huh? Oh, wait, what's a "multi-input slot"? Because in the cases



I don't see why one slot (not zero slots) is semantically different from two slots. Once the two-slot case gives an error message, we're no longer in the Scratch world of "no such thing as an error." And, I just noticed, the text of the error message has "input(s)," so it clearly anticipates applying to the one-slot case!

Huh? C'mon, I'm so not insulting you, I'm simply pointing out that many test projects fail once I forget to mark certain multi-slots as "widgets" (which prevents them from accepting parameter-substitution). I think we've found a good solution to the current confusion, and I'm glad with the outcome.

Well, that's alright for the custom block definition, but once you set up your expression for a certain number of expected arguments inside a ring you now have a different function (that one that's marked by a ring), and then that input is only variadic if it's collapsed. I don't think we're disagreeing here at all, are we? I'm a little bewildered by your recent mixing up of expressions and functions...

Yes, I was wrong regarding error messages of multi-slots. Come to think of it I now dimly remember that I had to make an exception for a single visible slot, because otherwise many examples used to fail. But that was so long ago I don't remember the actual cases any more. Maybe I we should simply change it and run all the tests again? :slight_smile:

Edit: (I've just tried it, and...) Ah, now I remember why I needed to make an exception for the single empty input, haha! Otherwise the variadic case of a collapsed multi-slot also throws an error. I guess that could be turned into a special case, albeit at the cost of introducing more complex runtime analyses with performance implications...

They teach us in teacher school never to say "oh, that's easy" to a student. Teachers mean it as "oh, don't worry, I can explain this so that you'll understand it and be able to do it," but students hear it as "you're stupid for not being able to do this easy thing." Same goes for "obvious."

About vari/poly, we're not disagreeing on substance, but I think it's confusing to use the same word (variadic) to mean one thing with respect to procedure definition and something different with respect to procedure use. In fact, in the case of procedure use, it seems to me that a visible empty input slot isn't anything-adic; it gets exactly one actual input value, or none if the conditions aren't met. The only case in which it'd be meaningful to talk about something being anything-adic in a procedure call is the case in which there is no visible empty slot! So I think I would prefer a use of language in which we say "when the user puts visible empty slots in the call to a procedure, that input's arity has been fixed; it remains variadic in the call only if there are no empty slots showing."

That would definitely be better for understanding. As for the efficiency issue, I don't really understand why there should be any connection in the first place between a single slot in the call and no slots in the call.
The former feels to me like a request for exactly one actual input value.
But you have to make the engineering decision.

P.S. I'm saying "expression" to emphasize that there may be several nested procedure calls in a single larger expression.

I just had to chuckle as I came across the following example in the reference manual:

You now, this script only works because the ask block's third input slot, which happens to be a "multi" one, behaves exactly the way you've criticized above in that it does not participate in the empty-slot-means-implicit-parameter scheme. I think this goes to show that we've put a bunch of subtle "do what I mean" gimmicks into Snap! - like the vanishing ring-slots when you drop a variable onto them - that generally work surprisingly well with users, until they progress to going meta on them.

It would be / will be fun to go through another round of design brainstorming if and how we can keep some of these affordances when going meta, or how to redesign them for v9!