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

Calling Object Oriented functions with . rather than :

Started by Geforce Fan, 11 January 2015 - 03:45 AM
Geforce Fan #1
Posted 11 January 2015 - 04:45 AM
Essentially, I want something like this

table = {}
table.text = "hi"
function table.print(self)
  print(self.text)
end
table.print()-->"hi"
basically, I want the user to call it with a . rather than :, but pass the self arg without having it put it in (). I've seen it done before, what do I need to modify to make this possible? This code will error because the self value is not defined.
Edited on 11 January 2015 - 03:45 AM
Lyqyd #2
Posted 11 January 2015 - 05:58 AM
You can't. Also, don't call your tables "table".

What you could do is set it up so that it uses an upvalue instead.


function createNewThingy(text)
  local obj = {}
  obj.text = text
  function obj.print()
    print(obj.text)
  end
  return obj
end
Geforce Fan #3
Posted 11 January 2015 - 06:39 AM
that was just an example, I know not to call my tables table :P/>
Gopher's Redirect API ( http://www.computerc...irect-ctrlkeys/ ) lets you call the functions with . yet they have self variables.
How is it not possible? What's he doing?
Bomb Bloke #4
Posted 11 January 2015 - 08:17 AM
Long story short, the functions you call don't require "self" variables. You never get access to the ones which do. The technique is loosely represented by this sample:

local myTable = {}

myTable.text = "hi"

function myTable.colonPrint(self)
  print(self.text)
end

myTable:colonPrint()  --> "hi"

myTable.dotPrint = function() return myTable:colonPrint() end

myTable.dotPrint()  --> "hi"

To be clear, the original functions still need to be called using colon notation - he's creating and calling wrapper functions (which don't require colons) instead, but the originals still needs to exist in order for the wrappers to work. Multiple objects refer to the one single memory-instances of the originals, though, so it's not as entirely inefficient as it sounds.
lucy-san #5
Posted 11 January 2015 - 10:05 AM
This might work:


foo = {}
foo.bar = function(self)
  print(self.baz)
end
foo.baz = "quix"
foo.bar(foo)

But it's really simpler and nicer to use colon instead, because all it does is just adding "self" as first argument, so You don't have to do it.
Also, just a tip: If You are doing OOP, check it out: https://github.com/d...key/lua-objects - it helps tremendously!
Edited on 11 January 2015 - 09:05 AM
MKlegoman357 #6
Posted 11 January 2015 - 11:56 AM
Actually TheOriginalBIT made it possible with metatables so functions could be called with both, dot and a colon. It's somewhere in his pastebin.
lucy-san #7
Posted 11 January 2015 - 02:52 PM
Here, just wrote it: http://codepad.org/DmeVHtyM

--# Your class:
local foo = {
	print = function(self)
		print(self.text)
	end,
	text = "foo bar baz"
}
--# Apply "hack"
local _foo = foo
foo = {}
setmetatable(foo, {
	__index = function(t, k)
		if type(_foo[k]) == "function" then
			return function(...)
				_foo[k](_foo, ...)
			end
		end
		return _foo[k]
	end
})
foo.print()
Edited on 11 January 2015 - 02:24 PM
GopherAtl #8
Posted 11 January 2015 - 03:18 PM
Long story short, the functions you call don't require "self" variables. You never get access to the ones which do. The technique is loosely represented by this sample:

local myTable = {}

myTable.text = "hi"

function myTable.colonPrint(self)
  print(self.text)
end

myTable:colonPrint()  --> "hi"

myTable.dotPrint = function() return myTable:colonPrint() end

myTable.dotPrint()  --> "hi"

To be clear, the original functions still need to be called using colon notation - he's creating and calling wrapper functions (which don't require colons) instead, but the originals still needs to exist in order for the wrappers to work. Multiple objects refer to the one single memory-instances of the originals, though, so it's not as entirely inefficient as it sounds.

Yawp, that's pretty much it.

Not as inefficient as it sounds, but not as efficient as just using the : forms, either. I did that with the redirect api so that the redirect objects would be identical to the native term object, which is java-side and so uses "." instead of ":" If I hadn't, you couldn't have used the redirect objects and term interchangeably. In cases where that's not an issue, it's probably not worth the overhead.
Edited on 11 January 2015 - 02:19 PM
ardera #9
Posted 11 January 2015 - 03:20 PM
you can do the following:

function safe(tab)
  local real = tab or {}
  local obj = {}
  setmetatable(obj,
  {__index = function(t, k) if type(real[k]) == "function" then
  return function(s, ...) local args = {...} if s ~= obj then table.insert(args, 1, s)
  s = obj end return real[k](s, ...) end else return real[k] end end,
  __newindex = function(t, k, v) real[k] = v end}) return obj
end

local obj = safe() -- either here

obj.text = "hi"
function obj:print()
  print(self.text)
end

obj.print()
obj:print()

--safe(obj) -- or here
Edited on 11 January 2015 - 02:23 PM
GopherAtl #10
Posted 11 January 2015 - 03:24 PM
you can… but you probably shouldn't. Unless you've got a good technical reason, this sort of thing just obfuscates what's going on with a script, which is generally bad. The people who would benefit from it being forgiving in the syntax aren't really helped in the long term by this sort of thing, it just allows them not to learn something about how lua works that they need to be mastering instead.
Geforce Fan #11
Posted 11 January 2015 - 05:21 PM
alright, thanks, I'll leave it to be called with :