lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


On this day of 03/15/2007 02:31 AM, Brian Hagerty saw fit to scribe:
> David Haley wrote:
>> How would you solve this problem? That is, how would you tell whether or
>> not a dot-syntax call should pass the table along as a first argument?
> 
> 
> That's an excellent question ... The short answer is that Lua doesn't
> need to translate to a.deposit(a,3), nor does Lua need to sore any extra
> information to say "this is a method".

[snip]

> In practice, the typical implementation of function calls, including in
> Lua, is to push a "call frame" (caller context and meta data) on to the
> stack *before* pushing the list of proper arguments.  That "call frame"
> always has a reference to the caller (so that when return is called in
> the function the computer knows where or to whom to return).

Caveat: I don't know how the Lua interpreter is actually implemented.
But, in general, I would say that the stack has a return address, saying
where to resume execution, which is a different from knowing "who"
called you. That implies to me that the "who" is some kind of object, as
opposed to simply a point of execution.


> Instead, the mere use of "self" in a function body would refer to the
> self/caller already found in the call frame, not to an argument in the
> stack of arguments.  So the only real difference is that a classic
> (non-OO) function does not refer to a "self" object, whereas an OO-like
> method does refer to a self object. "Self" (the caller) is already found
> in the call frame, and is not needed in the argument stack.

But this doesn't achieve the goal you want. Let's look at this:

function foo(a)
  -- 'a' is an Account object
  a.deposit(5)
end


The return address, as far as 'deposit' is concerned, points to the
instruction after the a.deposit(5) statement (which would be a return, I
suppose). The return address, for 'deposit', is not the table 'a'.

To make this work, I think you would have to give 'deposit' a way to
refer to the line of (byte)code, and examine it to see if the function
was called as the member of a table, and then use that table as the self
argument. That sounds like a fairly complex change, no? And also it
poses a fairly important extra problem, see below.

> This is basically how all local variables (non arguments) are handled --
> i.e. local variable (non arguments) are not found in the argument stack,
> they are found in the call frame.  Since self is just a special local
> variable, it does not need to be defined in a parameter list at
> definition time, nor does it need to be pushed on the argument stack at
> call time to be available at runtime.
> 
> Here's a quick summary: When a function body references self, it looks
> for it in the call frame (where the caller is always referenced), not in
> the argument stack.  If you don't reference self, you're a classic
> "function"; if you do reference self, you're an OO "method".

What happens if I do this:

local f = Account.deposit
local a = give_me_some_account()
f(a, 5)

In this case your approach breaks, because we pass 'self' explicitly.
Since the function no longer has 'self' as a first parameter, the
deposit function will see 'a' as its 'amount' argument, which is not at
all what we want.

I don't think the above situation is terribly contrived; I can imagine
some kind of method dispatcher that selects the appropriate function
from a table based on some criterion, and then calls the function by
passing in whatever object we need to operate on.

Eike's example is also good, and shows another case where trying to be
too clever with the colon syntax can break things fairly seriously.

Cheers,
- David

-- 
~David-Haley
http://david.the-haleys.org