instance/scope of self

General discussion about LÖVE, Lua, game development, puns, and unicorns.
User avatar
Rob.m
Prole
Posts: 23
Joined: Mon Mar 11, 2013 1:57 am

instance/scope of self

Post by Rob.m »

Hi all,
I have never done any OOP and I am having trouble with instance v refference and the scope of 'self'

I have been reading here -
http://www.lua.org/pil/16.html

But I still can't get it right.

The erroe I am getting is "44: attempt to index local 'self' (a nil value)"

Here is my code - line 44 is marked

Can someone please explain what I am doing wrong. Is there a good link to something about what I call 'scope'. What do you call it in LÖVE / Lua ??


Code: Select all

function love.load()
  objects = {}
  local button1 = newTextButtonToggle()
  local button2 = newTextButtonToggle()
  button1.xpos = 50
  button2.xpos = 150
  objects = {button1, button2}
end

function love.draw()
  for index = 1, 2 do
    local button = objects[index]
    love.graphics.print(button.currentvalue, button.xpos, button.ypos, 0, 1, 1, 0, 0, 0, 0)
  end
end

function love.update()
end

function love.mousereleased()
  local index
  local object
  for index = 1, #objects do
    object = objects[index]
    if object['click'] then
      object.click()
    end
  end
end

function newTextButtonToggle()
  return
    {
    xpos = 0,
    ypos = 0,
    width = 50,
    height = 20,
    initvalue = 'text',
    altvalue = 'alt text',
    currentvalue = 'text',
    click = function (self)
      self.currentvalue = 'clicked'
    end
    }
end

function love.load()
  objects = {}
  local button1 = newTextButtonToggle()
  local button2 = newTextButtonToggle()
  button1.xpos = 50
  button2.xpos = 150
  objects = {button1, button2}
end

function love.draw()
  for index = 1, 2 do
    local button = objects[index]
    love.graphics.print(button.currentvalue, button.xpos, button.ypos, 0, 1, 1, 0, 0, 0, 0)
  end
end

function love.update()
end

function love.mousereleased()
  local index
  local object
  for index = 1, #objects do
    object = objects[index]
    if object['click'] then
      object.click()
    end
  end
end

function newTextButtonToggle()
  return
    {
    xpos = 0,
    ypos = 0,
    width = 50,
    height = 20,
    initvalue = 'text',
    altvalue = 'alt text',
    currentvalue = 'text',
    click = function (self)
      self.currentvalue = 'clicked' -- *** This is line 44 ***
    end
    }
end
User avatar
Rob.m
Prole
Posts: 23
Joined: Mon Mar 11, 2013 1:57 am

Re: instance/scope of self

Post by Rob.m »

PS: Can I do this ? ie use a dot opperator on an indexed element of an array / table using var[inedex].

Code: Select all

objects[index].click()
And also cam I do something like this ? ie push elements onto an array / table stack using [] notation

Code: Select all

objects[] = object
objects[] = {click = function() ... end}
Last edited by Rob.m on Sat Mar 23, 2013 4:18 am, edited 1 time in total.
User avatar
Inny
Party member
Posts: 652
Joined: Fri Jan 30, 2009 3:41 am
Location: New York

Re: instance/scope of self

Post by Inny »

self is scoped through the colon operator. It's really just a syntax, here's some example code:

Code: Select all

object = {}
function object.foo(self)
  -- this function shows how things really work in Lua without the colon sugar synax
end

function object:bar()
  -- this function uses the colon to create an implied self local variable
end

object.bar(object) -- This is a valid call

object:foo() -- This is also a valid call
I believe this is called "Late Binding."
User avatar
Rob.m
Prole
Posts: 23
Joined: Mon Mar 11, 2013 1:57 am

Re: instance/scope of self

Post by Rob.m »

OK,

I think I have an idea and I will test it.

I can always do this the way you describe. That is declaring the parent object first

Code: Select all

object = {}
object.method = function (self) ... end
but this does not work

Code: Select all

object = 
  {
  attribute = 'value',
  method = function (this) ... end
  }
I assume that the reason is that because the Lua compiler is still parsing the contents of {} and as such it does not have a refference to 'this'.

I will try the colon notation and see if that causes a forward refference to 'this'.
User avatar
Rob.m
Prole
Posts: 23
Joined: Mon Mar 11, 2013 1:57 am

Re: instance/scope of self

Post by Rob.m »

Well I give up lol.

I have spent (wasted) a day on this and I have gotten nowhere at all.

I will explain what I want to achieve.

I want to have many objects such as buttons (images) and put events like mouseover mousedrop mousedrag mouseclick into the objects in such a way that the same events (as coded) may occure in other objects. ie they're instances of similar objects from the same template.

For the life of me I can't create duplicatable objects with events in them.

The reason why I want to do this is so that I can embed quads into the object for love.draw and also have the event in them so that mouse events just pass on the event rather than having to be aware of what object has what purpose.

I can't find/understand the scope of 'self'. I realise that half the day was wasted because I was using 'this' instead of 'self' due to experience with Javascript.

I have read all the Lua stuff I can find and it doesn't work once I try to return an object from within a function. ie an instance of an object. What is not working is the functions/events/methods within the object.

Acording to the Lua refference the stuff below should work but in their examples this is done in the global scope and not within a function. Once it's wrapped within a function I loose the scope of 'self'

Code: Select all

function newTextButtonToggle()
  object =  
    {
    xpos = 0,
    ypos = 0,
    width = 50,
    height = 20,
    initvalue = 'text',
    altvalue = 'alt text',
    currentvalue = 'text'
    }
  function object:click() self.currentvalue = 'clicked' end
  return object
end
I also tried -

Code: Select all

function newTextButtonToggle()
  object =  
    {
    xpos = 0,
    ypos = 0,
    width = 50,
    height = 20,
    initvalue = 'text',
    altvalue = 'alt text',
    currentvalue = 'text'
    }
  object.click =  function (this) self.currentvalue = 'clicked' end
  return object
end
I also tried -

Code: Select all

function newTextButtonToggle()
  object =  
    {
    xpos = 0,
    ypos = 0,
    width = 50,
    height = 20,
    initvalue = 'text',
    altvalue = 'alt text',
    currentvalue = 'text',
    click = function (self) self.currentvalue = 'clicked' end
    }
  return object
end
My first attempt was this -

Code: Select all

function newTextButtonToggle()
  return {
    xpos = 0,
    ypos = 0,
    width = 50,
    height = 20,
    initvalue = 'text',
    altvalue = 'alt text',
    currentvalue = 'text',
    click = function (self) self.currentvalue = 'clicked' end
    }
end
I am giving up for now.

If anyone can help then I would greatly appreciate if.

Thanks.

CODE DOES NOT OBEY


I tried everything that I could think of.
User avatar
Robin
The Omniscient
Posts: 6506
Joined: Fri Feb 20, 2009 4:29 pm
Location: The Netherlands
Contact:

Re: instance/scope of self

Post by Robin »

That last one should work. Could you upload a .love? That really helps us help you.

(Also, wrong forum. You wanted S&D instead of G.)
Help us help you: attach a .love.
User avatar
Rob.m
Prole
Posts: 23
Joined: Mon Mar 11, 2013 1:57 am

Re: instance/scope of self

Post by Rob.m »

For any other newbies, here is what I discovered.

'self' is not at all like any other language that I know.

For example. Javascript has 'this' which always points to something in the current scope. 'this' can inherit a sub part of it's 'parent' scope. Javascript can do this as it has scope inheritance and also an object model. Lua does NOT do the same.

In Lua 'self' is nothing more than a syntax convience and has the value nill (unset/null in other languages) UNLESS you specificly convey something from the parent scope.

'self' is simply an argument that you MAY pass on to a function if you choose to do so. NOTHING passes by itself.

It is just like any other argument except that there is one syntax convienence that it has over other arguments.

I would epect that there is one another exception to allow it to have precedence over LOCAL variables in the sub scope of a function. I haven't tested this.

So when you do -

object.method(self) then WHATEVER is before the '.' is passed to method as 'self' in the scope of method() It is not an iheritance, it is simply a conveyance. There is nothing different AT ALL to doing object.method(object) and then refference 'object' instead instead of 'self' whitin method()

The only difference perhaps is that it creates a naming (name space) CONVENTION for convienience.

the secondary synatx is also JUST a convienience.

When you do

object:method()

then WHATEVER is before the ':' is passed as the first argument to method() in the local scope of method() as 'self'

The point is that 'self' never exists UNLESS you specificly pass it into the sub scope of a funtion. By specifying (self) as an urgument OR using the object:method() notation.

if you want to pass an object as 'self' through several layers of scope then you have to specify it at every parent layer or it wont pass down.

also object:method() and object.method(self) are interchangable. both pass object as self to the child scope (function).
User avatar
Robin
The Omniscient
Posts: 6506
Joined: Fri Feb 20, 2009 4:29 pm
Location: The Netherlands
Contact:

Re: instance/scope of self

Post by Robin »

Rob.m wrote:also object:method() and object.method(self) are interchangable. both pass object as self to the child scope (function).
In function definitions.

Code: Select all

function something:method(...)
end
is the same as

Code: Select all

function something.method(self, ...)
end
and

Code: Select all

something:method(...)
is the same as

Code: Select all

something.method(something, ...)
except something is only evaluated once.

There is no magic here.
Help us help you: attach a .love.
User avatar
bartbes
Sex machine
Posts: 4946
Joined: Fri Aug 29, 2008 10:35 am
Location: The Netherlands
Contact:

Re: instance/scope of self

Post by bartbes »

Robin wrote: There is no magic here.
That's basically what lua tries to do anyway, there's very little magic in lua.
User avatar
Inny
Party member
Posts: 652
Joined: Fri Jan 30, 2009 3:41 am
Location: New York

Re: instance/scope of self

Post by Inny »

The short answer is that, yes, "self" is just a function parameter, and no, self is not like javascript's "this". It is completely typically of Lua code to use the self parameter explicitly everywhere else when the original scope has been lost, e.g., when calling a function in a subtable of your original object. Let me give you a little piece of code that will make it all more clear:

Code: Select all

function bind(obj, fn)
  return function(...) return fn(obj, ...) end
end

bar = bind(object, object.foo)
bar() -- equivalent to object:foo()
What's happening is that functions and the objects they belong to have no implicit connection. You must maintain the relationship between them yourself, either by keeping the function in the object it belongs to, or by explicitly binding it with a closure or some other means.


Just to drive the point home, this is also very valid in Lua:

Code: Select all

self = {}
function foo(x)
  self.x = x
end
In this piece of code, self has no special meaning.
Post Reply

Who is online

Users browsing this forum: No registered users and 6 guests