Stacksmith icon indicating copy to clipboard operation
Stacksmith copied to clipboard

Add support for closures (to Forge)

Open uliwitness opened this issue 4 years ago • 3 comments

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

uliwitness avatar May 19 '20 08:05 uliwitness

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

  1. 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"?)
  2. it might be confusing to have and that isn't a boolean operator, or do that isn't a do command. OTOH this could be used in many places where do used to be used, and we haven't implemented do yet.
  3. the way we distinguish a one-line take followed by a do command from a multi-line take is whether there's a return after the do or an argument, so no ambiguity.
  4. Scripters already have to learn the different ways to format a then for if, so using it here again kinda makes it more consistent.

uliwitness avatar May 19 '20 09:05 uliwitness

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 the my or of 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 having put "cd btn 5" into myHandler; get myHandler(43) invoke a function run 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 uses do 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.

uliwitness avatar May 19 '20 09:05 uliwitness

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.

uliwitness avatar May 19 '20 15:05 uliwitness