Stacksmith
Stacksmith copied to clipboard
Add support for closures (to Forge)
We want an English-like syntax. Best I could come up with is
take <parameters>|nothing then
-- commands go here
end take
and
take <parameters>|nothing then -- single command goes here
and
take <parameters>|nothing
then -- single command goes here
This reads fairly well when e.g. used in a function:
put sortedByName(myAddresses, take firstPerson, secondPerson then return firstPerson > secondPerson) into sortedAddresses
Alternate spelling that looks neat would be
take <parameters>|nothing and -- single command goes here
as well as
take <parameters>|nothing and do
-- commands go here
end take
and maybe even
take <parameters>|nothing and
-- single command goes here
Considerations
- it might be confusing to have
then
re-used in something not conditional (will this lead to the same kind of confusion as people talking of "if loops"?) - it might be confusing to have
and
that isn't a boolean operator, ordo
that isn't ado
command. OTOH this could be used in many places wheredo
used to be used, and we haven't implementeddo
yet. - the way we distinguish a one-line
take
followed by ado
command from a multi-linetake
is whether there's a return after thedo
or an argument, so no ambiguity. - Scripters already have to learn the different ways to format a
then
forif
, so using it here again kinda makes it more consistent.
Implementation Notes
- All closures are functions. We don't need a "command closure" syntax. You can choose to not have a return statement, though, so this is mostly relevant at the site of use
- For a quick win, one could probably make all closures handlers in the script they're declared in with a unique name, and pass that handler name and the object descriptor of the script to handlers to call.
- We could probably build closures that are real objects and capture any outside variables used inside (as well as any unquoted string literals that might be filled by using the
do
command or the like) as properties, re-map their uses to be property accesses (implicitly adding themy
orof me
), then calling a closure would just invoke a certain handler on that object. That would not require a new data type, but would require the ability to "attach" additional objects to an object's script. - We need a syntax for calling a handler whose name/object descriptor is stored in a variable. Do we just say "if there is a handler call, and there already is a variable with the name of the called handler, assume it contains a handler name or closure and call that instead"?
- If closures are real objects, we should probably make that an implementation detail. Maybe make their object type "function" and say
function takeHandler:15 of cd btn 5
as its object descriptor, then only permit calling function objects. All other object descriptors would result in an error. Can always widen this, but havingput "cd btn 5" into myHandler; get myHandler(43)
invoke a functionrun
on a button seems very confusing and un-intuitive. Very programmerish, but violating the illusion of buttons being buttons and functions being functions. Just because closures are ad-hoc objects under the hood doesn't mean we should force scripters to be aware of that. - Closures that take no parameters are written as
take nothing then return gMyName
etc. - Can we come up with a syntax for explicit capture lists? Given how dynamic HyperTalk is, I think the natural way to do capture is implicitly. But the presence of the
do
command makes that hard (do all variables become properties just in case someone usesdo
to declare a variable, change it in the closure, expecting it to be modified)? But it would still be nice if we could explicitly capture variables for a safer programming style.
If anyone has suggestions, it would be appreciated. Especially something that reads English in most cases, doesn't use nerdy terminology or big words, and fits into HyperTalk's "the value has the type, not the variable" (aka "everything is a string") world.
TBD - Can we make closure parameters more self-explanatory? Right now if a command expects errorCode, errorMessage in that order, and I reverse them, there's no way to detect that.