function Stack(n):
dim stack[n]
return {
stk: stack,
ptr: 0,
push: function(x): m.stk[m.ptr] = x: m.ptr = m.ptr + 1: end function,
pull: function(): m.ptr = m.ptr - 1: return m.stk[m.ptr]: end function
}
end function
BrightScript Debugger> s = Stack(100)Whaaat?
BrightScript Debugger> s.push(42)
Invalid value for left-side of expression. (runtime error &he4) in pkg:/source/main.brs(6)
"TheEndless" wrote:
My guess would be it's because you tried to use a locally scoped variable with the same name as the function, so m.stk is actually equal to the function Stack() and not your array stack.
"EnTerr" wrote:
I don't even know how the heck does this mis-happen? Since all local variables are resolved to indices at compile-time and that did not happen at compile time for `stk: stack`, doesn't that mean compiler first checked the global function table - as it was at that point - before locals table? And if so - and here it goes crazy - that will make it non-deterministic, since what if "Stack()" was not the current or previous function but defined a few lines later? Wouldn't then `stk: stack` usage resolved into a local?
sub foo():[spoiler=spoiler:3hkbg4ey]BrightScript Debugger> foo()
bar = 1
foobar = bar
print foobar
end sub
'
' ... big chunk of code here ...
'
sub bar():
end sub
"EnTerr" wrote:"EnTerr" wrote:
I don't even know how the heck does this mis-happen? Since all local variables are resolved to indices at compile-time and that did not happen at compile time for `stk: stack`, doesn't that mean compiler first checked the global function table - as it was at that point - before locals table? And if so - and here it goes crazy - that will make it non-deterministic, since what if "Stack()" was not the current or previous function but defined a few lines later? Wouldn't then `stk: stack` usage resolved into a local?
Necessarily speaking from my Equus asinus, i experimented and seems that BrS compiler does "hoisting" for global functions. What would you expect foo() to print here:sub foo():[spoiler=spoiler:2j6ds0kf]BrightScript Debugger> foo()
bar = 1
foobar = bar
print foobar
end sub
'
' ... big chunk of code here ...
'
sub bar():
end sub
<bsTypedValue: Function>[/spoiler:2j6ds0kf]
The result is startling for couple of reasons. First, bar gets treated differently depending on which side of the assignment operator it is! When it is a L-value, being assigned to - it is a local variable (we see later the global did not get mangled). When it is a R-value (to the right of assignment) though, it returns the global.
And second (this requires a little more thinking but): when compiling foo(), how did compiler know there will be a global bar() - since it comes much later textually? The explanation is "function hoisting" - it has gone first through all source to peek at all function names before starting to compile function bodies. (I know function hoisting from Javascript and odd things happen there too because of it).
Weird, huh! And yet there is not even a warning during execution.
"TheEndless" wrote:Nope, not always. See the example i gave, read the juxtaposition of Lvalue and Rvalue. Therein lies the problem, it an easy-to-learn language does not make. It should not flip-flop in treatment of names depending on which side of "=" they lie.
I'm not sure why you'd be startled by that result. It's already been established that functions always take precedence over variables (FWIW, I'm not happy about it either).
I'd also expect it to do "function hoisting".. otherwise you'd have to be very deliberate in how you structure your BRS files,Which is why hoisting was done, so that you don't have to put Main() at the very end and also can have mutually-recursive functions (foo() calls bar(), bar() calls foo()). I did not object to it - rather pointed it was done and the quirks it adds.
and you wouldn't be able to define "methods" in the construction of an AA-based "class".That... that's completely unrelated. This
obj = {relies neither on hoisting nor on named-function globality. Or did i misunderstand you, through example if i did.
f: function(): return m.field: end function,
field: 0
}
"EnTerr" wrote:
Hm, did you really have to quote the whole shebang i said?
"EnTerr" wrote:
Nope, not always. See the example i gave, read the juxtaposition of Lvalue and Rvalue. Therein lies the problem, it an easy-to-learn language does not make. It should not flip-flop in treatment of names depending on which side of "=" they lie.
"EnTerr" wrote:
That... that's completely unrelated. Thisobj = {
f: function(): return m.field: end function,
field: 0
}
relies neither on hoisting nor on named-function globality. Or did i misunderstand you, through example if i did.
Function MyClass() As Object
this = {
ClassName: "MyClass"
MyMethod: MyClass_MyMethod
}
Return this
End Function
Sub MyClass_MyMethod()
' Do Something
End Sub
"TheEndless" wrote:Don't have to copy&paste. I do select + delete. "Cut on byte pollution, save the environment" 😄
I was too lazy for cut and paste, so just hit the quote button on your previous post. So, no, I didn't have to quote the whole thing... 😉
And that is the crux of the matter!"EnTerr" wrote:
Nope, not always. See the example i gave, read the juxtaposition of Lvalue and Rvalue. Therein lies the problem, it an easy-to-learn language does not make. It should not flip-flop in treatment of names depending on which side of "=" they lie.
That's an issue of scope, I think. The Lvalue is a locally scoped Set, so there's most likely a locally scoped "bar" variable on the stack at that point. You just can't get to it, because as an Rvalue, it's evaluated to the global function instead.
I rarely use anonymous functions in my code, so I was referring to something like this:Curious. You wouldn't happen to come from C++ provenance, are you?Function MyClass() As Object
this = {
ClassName: "MyClass"
MyMethod: MyClass_MyMethod
}
Return this
End Function
Sub MyClass_MyMethod()
' Do Something
End Sub
Without function hoisting, that wouldn't be possible, because MyClass_MyMethod wouldn't exist, yet, when MyClass was defined.Yeah, so what? 😄 That would just follow from (an imaginary) general rule that a function - MyClass() in your case - can only use other functions defined before it. In other words MyClass_MyMethod() would have to be textually written before it. Which turns out to be reasonable requirement, if you have done programming in Pascal/Modula. Hoisting is needed in the cases of circular reasoning, though that also has a work-around - forward declarations.