Scoping in StackTalk
In most programming languages, especially more modern ones, scoping is usually handled "lexically", which typically implies closures. The way this usually plays out is that if you're returning a function from a function, the variables in the containing function can be referenced by the returned fuction. JavaScript might be the most famous example of this.
StackTalk works a bit differently. Quotations are lists of symbols, and do not capture state. Objects -do- contain state. The 'host' object a quotation is run inside of determines what stacks it can see. This also means that scope is largely dynamic.
Lobby
In the tradition of Io and Self, there is a Lobby object. It's treated specially in that it's the default scope, and also the bottom of the me stack. It is also the global namespace. Stacks populated in the Lobby are visible to all scopes, but are hidden by stacks defined in a given object.
Changing the current scope
There are a few ways that you can manipulate the scope that quotation executes in. The simplest way is to put objects on the me stack, since the top of the me stack is the first scope where stacks are looked up.
There are also some dedicated words for manipulating the me stack. The first one is ask.
ask takes an object and a quotation. It pushes the object to the top of the me stack and then runs the quotation. After the quotation is done, the top of the me stack is dropped. ask is meant for situations where you want to extract some information from an object without keeping it around (usually because you have it stashed on a stack for easy access).
ask: [ obj quotation -- ... ]The next one is do. do works like ask, except, instead of dropping the top of the me stack, it pops it onto the value stack It's good for object setup, among other things
do: [ obj quotation -- ... obj ] Finally, there is your. your is used to interact with the scope one layer down the stack from the current layer. This is useful for pulling information out of specific stacks in your caller, such as for treating some stacks like named arguments. Beause it uses existing stack entries, it only takes a quotation as an argument
your: [ quotation -- ... ] Creating objects
StackTalk has a few facilities for creating objects as well as performing code re-use.
obj
You can use obj to create a new object. It takes a quotationand executes it in the scope of the new object.
20 >spawn-x 40 >spawn-y
obj[
your[ spawn-x ] >x your[ spawn-y ] >y
pos: fn[ x. y. ]
move: fn[ y: += x: += ]
put-at: fn[ y: drop x: drop >y >x ]
]This example creates an a 2d coordinate and gives it some basic methods. You can create objects basically on demand like this.
Modules
Modules are StackTalk's current mechanism for basic code-reuse. you can define one like so:
coord: module[
pos: fn[ x. y. ]
move: fn[ x: += y: += ]
put-at: fn[ y: drop x: drop >y >x ]
]Then, the example above could be rewritten like so:
20 >spawn-x 40 >spawn-y
obj[
use[ coord ]
your[ spawn-x ] >x your[ spawn-y ] >y
]Modules work by defining an object based on the supplied quotation. Then, when you use a module in a scope, the stacks are copied from the module to the scope that is using the module. The stacks are copies, not references, so changes to the stack in one usage of a given module won't automatically propogate to other usages. If you want to share state between users of a module, you can put an object on the relevant stack.