Nov 02, 2018

What do you think?

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

What do you think this will print?

local t = {
    bar = 100
    f = function() {
        print(this.bar)
    }
}

t2 <- {
    bar = 200
}

t2.f <- t.f

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

r.do_call(t2.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 06, 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 13, 2018
If you define do_call as f(f) I think you'll get 200

Howard

5d ago
Did you really just feel the need, or was Squirrel lacking?

Ron Gilbert

5d ago
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

16h ago
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) {
        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) {
        f()
    }
}
Here are the rules for commenting.