Closed Ilazki closed 4 years ago
We consider it desirable. Unqualified assignment in MiniScript always assigns to the local scope.
To update a value in the outer scope, use the outer
keyword:
outer.count = count + 1
(That said, I do appreciate the input and the attention to detail! Please consider joining us in the forums or the Discord chat, both accessible via https://miniscript.org .)
Okay, I completely missed that because I found out about MiniScript from a game using it (Grey Hack) and was using the command-line interpreter to test things externally. The quick-ref is pretty good for getting into it quickly if you're familiar with other languages, including mentioning the @fun
oddity, but says nothing about unusual scoping rules. Knowing about that helps a bit.
That said, I'm not sure that needing outer.foo
is a good idea in general. It violates expectations regarding lexical scope and has a default behaviour that looks like a bug. Local assignment should be in respect to the entire lexical scope (in contrast to global scope), not the immediate block.
It also seems to have unusual behaviour if functions are nested more than two deep. A silly example in the style of the previous ones:
closure3 = function ()
count = 0
return function ()
return function ()
outer.count = count + 1
return outer.count
end function
end function
end function
c3t = closure3()
c3 = c3t()
print [c3,c3,c3] // [null, null, null]
// Runtime Error: Undefined Identifier: 'count' is unknown in this context
If I instead move count
one scope inward, everything works again:
closure3 = function ()
return function ()
count = 0
return function ()
outer.count = count + 1
return outer.count
end function
end function
end function
c3t = closure3()
c3 = c3t()
print [c3,c3,c3] // [1, 2, 3]
I can't tell if that's a bug or if there's some non-obvious thing I need to do to deliberately climb through the outer scopes, so I'm unsure if I should report that, re-open this, or if there's a trick you can name.
Interestingly enough, this all started because I ran into a bug in Grey Hack's scripting where functions created in-game lose their outer scope and reported it then decided to dig further. The behaviour I mentioned there is similar to what I just encountered here while trying outer
with a depth of more than two functions, so now I'm wondering if they're connected.
MiniScript's lexical scoping does not search arbitrarily deep. It only checks, in order: the local scope, the outer scope, and the global scope. Nested functions are not closures in the sense you're thinking of them, though in most real (not contrived) use cases, they can be used in the same way.
This is also by design; while there are many valid use cases for an inner function (supplying a comparison function to a sort routine, a function to apply to a list or map, etc.), if you find yourself going deeper than that, then probably a class/object would be clearer. I realize of course that fans of functional programming may disagree. But this is part of the "mini" in MiniScript, i.e., we strive to keep the language simple and easy to understand, especially for new programmers.
I've been testing in the MiniScript command line interpreter and noticed a problem with using closures. They work fine if a value in the outer scope isn't changed by the inner, but attempting to update the value acts as if it's been locally defined in the inner scope rather than outer.
You can currently cheat it by using a complex type (list or map) to get the correct behaviour but this is undesirable.
Examples: