This is a read-only snapshot of the ComputerCraft forums, taken in April 2020.
Joe3000's profile picture

"self" not working?

Started by Joe3000, 25 May 2015 - 11:43 PM
Joe3000 #1
Posted 26 May 2015 - 01:43 AM
Alright, I am very confused… I have recently taken probably a 3+ year break of CC but im back again! And I decided to use CC to attempt to learn about A* pathfinding. Howver, I quickly ran into a really weird error that I don't understand at all. When attempting to do object orientated programing, I keep getting nill values! For example:


local nodes = {}
function createNode(x,y)
  node = {
	xpos = x;
	ypos = y;
	parent = null;
	hValue = 0;
	gValue = 0;
  
	getXpos = function(self)
	  print(self.xpos)
	end;
  
  }
  return node
end
nodes[#nodes] = createNode(1,1)
nodes[0].getXpos()

The program breaks at the "print(self.xpos)" line for attempting to index a nill value. I don't understand this problem because I have a program that I made years ago on a different version of CC that utilizes this kind of programing and still works. Here is a small snapshot of code:

function background()
  stars = {
	xpos = math.random(l);
	ypos = math.random(h);
	xvel = 1;
  
	draw = function(self)
	  term.setCursorPos(self.xpos, self.ypos)
	  term.setBackgroundColour(colours.black)
	  term.setTextColour(colours.white)
	  term.write(".")
	end;
  
	update = function(self)
	  self.xpos = self.xpos - self.xvel
	  if self.xpos <= 0 then
		self.xpos = l
	  end
	end;
  }
  return stars
end

This works in my game perfectly fine. Now here is where things get really interesting! When I take this piece of code and paste it into a NEW program created on on the NEW version of CC (and I define all the variables such as h and l) It doesn't want to work anymore. And again, the program breaks on the line where "self.[whatever]" is called. I honestly don't think it has anything to do with the fact that this code came from a different version of CC because I'm pretty sure the files don't have anything in them that is able to tell the os which version of CC they were made in. But I still don't know what is going on here? Does anyone know what is happening? Here is another piece of code that breaks, just because its simpilar and easier to understand (maybe):


player = {

  xpos = 5;

  getX = function(self)
	print(self.xpos)
  end;
}
player.getX()
KingofGamesYami #2
Posted 26 May 2015 - 01:48 AM
Your example will not work, but a simple change will make it work:


player = {

  xpos = 5;

  getX = function(self)
        print(self.xpos)
  end;
}
player:getX() --#notice the colon ( : )

When called like this, the table is passed to the function. It has the exact same functionality as this (but is shorter):

player = {

  xpos = 5;

  getX = function(self)
        print(self.xpos)
  end;
}
player.getX( player )
Anavrins #3
Posted 26 May 2015 - 01:51 AM
"self" only work when you call your function with a colon, player:getX() should work.
Edited on 25 May 2015 - 11:51 PM
Joe3000 #4
Posted 26 May 2015 - 01:51 AM
OH. MY. GOD. THANK YOU SO MUCH!!! I remember YEARS ago when I first learned how to do this in lua I had such a problem figuring out what was wrong with my code! and then after a week of punching myself in the face I discovered this and told myself I would never forget it again! Well aren't I an idiot hahaha thank you so much!!! <3
InDieTasten #5
Posted 26 May 2015 - 01:52 AM
If you are calling a function, that receives self as a normal variable, this doesn't add any special features. You could name the var however you want. But when it comes to calling the function, you would need to provide this argument, otherwise it'll be nil, and as you are indexing this value, you are getting your nil exception. You probably search for something like node[0]:getX()
notice the :, instead of . This will automatically pass the value infront of it to be passed as first argument.

this sugar can be used when defining the function. Then the var name will be set automatically to self, which is where the convention comes from.

I'm now being ninja'd like 5 times xD
Bomb Bloke #6
Posted 26 May 2015 - 02:06 AM
If you're going to use that sort of structure, consider the use of metatables. The specific feature you're after is to link all your "object" tables to one single table containing your functions, so that you're not storing redundant copies everywhere.

Eg:

local myFuncs = {
    ["print"] = function(self)
        print(self.text)
    end
}

local function newOb(text)
    local results = {["text"] = text}
    setmetatable(results, {["__index"] = myFuncs})  -- Attempts to reference values in "results" that don't exist there, will instead get them from "myFuncs"
    return results
end

local moo = newOb("Hello")
local moo2 = newOb("World")

moo:print()   -- Call the function with the "moo" table as a parameter
moo2:print()  -- Call the same copy of the function with a different table