What do you think?

Nov 02, 2018

Doing testing on closures. This also makes my head hurt.

What do you think this will print?

local t = {
    bar = 100
    f = function() {

t2 <- {
    bar = 200

t2.f <- t.f

local r = {
    bar = 1000
    function do_call(f) {


Now with Answers

Well, not answers in the definitive truth of the universe way...

If you compile and run this code in Squirrel, the answer is 1000. This surprised me a little. I was expecting 200, but would have taken 100. As I build this new compiler, being some-what compatible with Squirrel is important, since I have a shit-lot of code already written in Squirrel that needs to run in the new compiler.

My new language (called Dinky, btw) is about 90% syntactically compatible with Squirrel, but subtile functionality like what 'this' means might be more important since it can fundamentally change the nature of the game's scripting code I've already written.

I don't think I've ever written anything as convoluted as the last function call shown, so it might not be important to adhere to, and instead treat 'this' more conventionally. I do wish I knew what the philosophy behind Squirrel's notion of 'this' is. I'm hesitant to just change it and miss some genius buried in why it works that way it does.

Currently my compiler and interrupter produces the same output as Squirrel and I'll probably stay with that until I understand the 'why' a little better.

I've spent three weeks on the new compiler and am now ready to move it over the my new game and start using it. I figure it will take a good part of this week to get the game fully functional under the new compiler and back to where I was with Squirrel.

Valentin Nov 03, 2018
I think it should print 100, because the this in f was lexically scoped to t.
This seems like the least surprising choice.

Though you could go for a dynamic scope and print 1000 because it's called on r,
but that's a lot harder to reason about when reading the code.

Zak Phoenix McKracken Nov 03, 2018
t2.f is not defined.
Anyway, if t2.f<- t.f is allowed, then it should print 100

Smoo Nov 03, 2018
I think the "this" makes the interpretation a little less easy. It _could_ be lexical binding, and "this" is always fixed. Does that imply that all closures only close over "this", and cannot refer to nested bindings, or is this just convenience?

Alternatively, it could be going "this" as sort an implicit parameter of its execution (in method form, say), like python and javascript-this (but not javascript closures in general). If that is the case, I would either expect it be unable to resolve "this" (because it was called as a free function), or to return 200 if the expression "t2.f" implicitly returns the function bound to t2.

I think it largely depends on what sorts of patterns you are trying to support.

dos Nov 03, 2018
I think I simply can't tell without knowing how "this" works in this language.

Chris Nov 03, 2018
I'd expect it to print 200.

The actual function you're calling is on the t2 object, where bar==200.
I first thought it would be 100 but the way it appears you want the language to work seems to me to be that in the 'local' calls, you're both defining and instantiating an object.
So then when you define the f function on the t2 class which is also instantiated, you're actually making a copy of the function into the t2 object.
So then when you call it the instance that t2.f will see will be the one where bar==200.

Alwin Garside Nov 03, 2018
What you just should do to avoid confusion is throw an error saying "‘this' is not available in closure scope".

Closures shouldn't be treated as being part of the class/object they are declared in and not magically inherit any variables unles specifically declared using a ‘use' or ‘.bind()'

Jeffry Houser Nov 04, 2018
It is not obvious to me what the difference between the = operator and <- operator is, and the local namespace is not a namespace in any language I use.

I would have guessed 100, but If I convert this to JS, I get an undefined.

Sander van Dragt Nov 04, 2018
Undefined because this should point to the scope of the function where there is no bar in any of the closures.

Chris Nov 05, 2018
> this should point to the scope of the function

Why should the 'this' keyword point to the scope of the function? Should it not refer to the scope of the enclosing object like it does in other languages?

Siddesh Nov 07, 2018
OMG!  You really created your own language?  
BTW why did you name it "Dinky"?

Gene Nov 12, 2018
Are you... open sourcing the engine?..

Harun Nov 14, 2018
If you define do_call as f(f) I think you'll get 200

Howard Nov 16, 2018
Did you really just feel the need, or was Squirrel lacking?

Ron Gilbert Nov 17, 2018
Squirrel is a great language and it did 95% of what I needed.  Mostly I wanted const folding and the ability to precompile to cross platform byte code, both of which squirrel couldn't do.  I also removed some features I never used for s slight speed gain (but probably not worth it).  But mostly, I just wanted to go it.

Ferdi Nov 21, 2018
I'm in no way a real programmer, but my view is:
Object R has bar set to 1000, so if the function is print(this.bar) it seems sensible to me that it returns the bar of the current object, hence it returns 1000. It just takes the function from another object,rather than the object itself it would not take that bar along.

I interpret it as a very picky inheritance.
Even if it would have been:

local r(t) = {
    bar = 1000
    function do_call(f) {
where (t) indicates inheritance it would return 1000, as bar is overwritten after the init, without the bar=1000, it would now return 100, as it is assigned in t.

Finally without inheriting from t and without assigning bar, I'd expect an error, because there is no bar assigned.
local r = {
    function do_call(f) {

Davide Dec 02, 2018
I never used the Squirrel Language, so what I say is likely inaccurate
but, by reading the Squirrel documentation, it seems every function in Squirrel has an implicit "this" parameter, and every direct function call passes its "this" implicitely:
explicit: obj.f() <--> f(obj)
implicit: f() <--> this.f() <--> f(this).
So f is like a static function, and r is calling it passing its "this" value as first parameter.
It's not a real closure, because "this" in such sense is just a function parameter, not a free variable.
t2.f <- t.f
is just assigning a function pointer, it's not storing a <faddress, functionaddress> pair,
neither is compiling a generated class (as it would be in C#).

It seems you have to use explicitely a function called bindenv() when you want that "faddress" is used for "this" when the function is called.

Actually, I like it, once you've got that by default what "this" is passed it's decided by the caller, the results are quite predictable. While if you want to implement more complex metaprogramming stuff you must explicitely use bindenv().

MrKii Dec 21, 2018
I don't know what is the result, but if I had written the compiler it'd say "wrong placement of the opening braces" :_)

patsm00re18 Feb 11, 2019
Thanks for taking this opportunity to discuss this, I feel fervently about this and I like learning about this subject.

Click this https://games.lol/brain/

Julian Apr 20, 2019
Weird, in JavaScript it's undefined:

t = {
    bar : 100,
    f : function() {
        console.log("The answer: " + this.bar)

t2 = {
    bar : 200

t2.f = t.f

r = {
    bar : 1000,
    do_call: function (f) {

r.do_call(t2.f)  // prints undefined
t2.f()  // prints 200

I guess it doesn't handle closures that well.

lennon Apr 28, 2019
If prints 1000 it's using the function of "t" with the "bar" of "r".
Since the function is in "t", that means that "this" is interpret from "r". It's dynamic. I like the languages that do this stuff.