<A rare and precious video walking us through Boxe...
# linking-together
k

A rare and precious video walking us through Boxer.

i
This is fascinating. I've heard of boxer so many times, but never actually seen it before. It's funny to me that they bumped up against many of the same issues / questions we're grappling with in my current Ink & Switch project: • When duplicating canvas objects that have behaviour, should those duplicates be a deep copy with no shared internals, or should there be some amount of sharing? How do you approach masters/instances? How do the answers change as a result of this taking place in a spatial environment? How do these answers relate to scoping? • What about names? Where do names live? Why do you give things a name? How do you refer to things that don't have a name? • How do you connect things together? How do you multiplex / split? How and when do you see the connections? • Where do values live? If you're going to execute some smaller part of a larger program, how do you feed it values? When do you see those values? • How do components nest? How do you expand / contract components? How does information flow across component boundaries? • What interface elements need to be big because they need to be easy to see, and which ones need to be big so you can touch them, and when are these in tension? etc etc. These are all common questions when designing a visual programming system, naturally. But what's funny to me is just how damn similar Boxer looks to some of the hacky / placeholder prototype work we're doing right now, and the small handful of differences. (Wish I could link to it.)
k
@Samuel Timbó Call out to unit.land at the end!
b
see also some responses by diSessa: https://groups.io/g/boxer-sunrise/topic/108687245. ---- I'm fascinated with Boxer's
tell
(aka
ask
) mechanism for "OOP": It simply takes a piece of code to execute in another context. E.g. if you have 2 turtles, you can
tell turtle2 right 90
(the inner code e.g.
right 90
can be wrapped in a box but that's optional for short things). Pedagogically, this allows students to operate multiple stateful copies, without having to first learn encapsulation, interfaces, and having to expose a "method" for whatever you want to tell them to do (which requires being comfortable with defining functions). The only other language I've seen with such model is Snap! (see "Sending Messages to Sprites"). [Well, does JS depracted
with
statements count? But JS has real methods too, plus it lacks an expression form.]
This mechanism however comes at pedagogical cost wrt. parameters, due to scoping 🤔: E.g. consider "firing an arrow" in Snap! where you want to initializing a new sprite at x,y position matching current sprite. You can't just tell new sprite to "move to x: (my x) y: (my y)" block to the new sprite since the whole thing including "my x" will be evaluated in new sprite context 😞 • In Snap!, the solution is to first introduce local variables, set them to parent's x and y, then you can refer to these variables inside the envelope. (That works cause Snap does have Scheme-like lexical scoping, it's only "current sprite" operations like position that are affected by
tell
context.) This is rather complex. • In Boxer, local variables wouldn't solve this either, all name lookups are affected by
tell
. This is consistent with Boxer's "copy and execute" mental model of how calling a doit box works. (Opt-in lexical scope is possible via ports, but that's really an advanced escape hatch.) So, how do you pass a block of code to be executed in new context yet parametrize it from current context?! Boxer added a special
^
syntax just for that:
For example, ASK JOE FORWARD X has JOE use his X, while ASK JOE FORWARD ^X has JOE use the X available where ASK appears.
— from "Boxer Structures"
So, syntactically
^X
etc looks kinda like templating [btw Boxer has a generic "semiquote" too —
build
, with a different syntax]. (Semantically, this is not really templating but a 2nd runtime context Boxer interpreter keeps track of) Like all templating, it'd get horrific if you need more levels deep... In regular OOP, this Just Works when you do something like
arrow.moveTo(this.x, this.y)
— the argument expressions are computed in the caller's environment, then method body is evaluated in target's environment. The call boundary is also the
this
switch boundary! And one can become productive before having to think too deep about that.