Classes And Methods

lua-users home

[!] VersionNotice: This tutorial uses Lua 4.0 concepts of tags and tag methods, which have been replaced by metatables and metamethods in Lua 5.0. See LuaClassesWithMetatable.

Class tables

Tables can be used as associative arrays. This functionality allows us to store functions in a class table, ie. with the function name mapped to the function.

A = {}

function A:add(x,y)
  return x+y

print( A:add(1,2) )  -- prints 3
In this example we can only have one instance of the class A. If we wanted to make another instance we could make a table be, (eg. B={} ) and copy all of the methods from A into B.

Tag methods

Multiple instances of a class can be created by using Luas tag methods. The tag methods can be used to redirect function requests from a class instance to the class function table. ie. We no longer need to copy all of the classes functions into each instance of the class. eg.

-- settag() returns a table "{}" which has been tagged with a new tag value
A = settag({},newtag())

-- use the index tag method to redirect a request for a function to the 
-- class function table
settagmethod(tag(A),"index", function(t,f) return %A[f] end)

function A:new(x,y)  -- create an instance of class A
  local t = {x=x,y=y}
  settag(t,tag(A))  -- tag the new table to tell it what its class type is
  return t

function A:add()
  print (self.x+self.y)

function A:sum(a)
  assert(tag(self)==tag(a)) -- check they are same class
  print (self.x+a.x,self.y+a.y)

a = A:new(7,9)  -- new instance of A

b = A:new(2,4)  -- new instance of A

a:sum(b)  -- "sum" of 2 instances
However there are problems with the example shown.
settagmethod(tag(A),"index", function(t,f) return rawget(%A,f) end)
a.number = 123
a:number()  -- try and call x
This will result in an error as we try to call a number.
a.sum = 7
print( a.sum )  -- should this print <function> or 7 ? (it prints 7)

Resolving name clashes

This problem cannot be resolved as the call request does not inform the tag method which type is required. We can take a preference, eg. class instance value takes preference over the function table value. (Doing it this we could support function overloading.)

If the function table takes preference, we could use the gettable tag method to check whether a method exists in the function table A first, eg.

settagmethod(tag(A), "gettable", 
            if rawget(%A,k) then
              return rawget(%A,k)
              return rawget(t,k)
          end )

Unified methods: This problem has been solved in Sol (a fork of Lua by Edgar Toernig) by introducing Unified methods. Here, a function/method table is associated with a tag. What happens when a table lookup occurs depends on how the lookup was invoked. ie. and a:foo have different implications. looks for a member called "foo" and a:foo looks in the tagged function table for a method "foo". Thus, you can have two members, one data and one a function happily living side by side, with no clash.

What is the motivation for wanting methods and "data" in separate namespaces? Sol's unified methods are cool, allowing methods and data to be separated and also providing an easier system than tag methods. However I thought the main point of it was to allow class methods to be implemented without each table holding its own copy. If the answer is because some class instance needs to allow the end-user to add arbitrary data fields directly, I would say maybe that's not good design and the operations should be implemented as a stand-alone functions rather than class methods, or the field access should be done through a controlled interface. (I looked at PythonDictionaries. Isn't this issue the result of attempting to emulate some interface in Python rather than provide one suitable for Lua?) --JohnBelmonte

I'm not sure what your alternative implementation is wrt to a controlled interface. Would this resolve the / t:foo problem (and allow arbitrary data to be stored)?. It looks like the existing Lua tag method system, or modified? I don't think this is just the result of trying to emulate Python, there is a conflict here. ie. your implementation is restricted. I thought the metamechanisms were supposed to be flexible enough to implement features like this. Is this a question of implementation style? The problem could be avoided by using stand alone functions but I dont think thats very tidy (and in this example, unlike Python) --NDT

Take a container written in C++ for example. The field access is controlled-- either through operator[] or dedicated member functions. There is no ambiguity between what is a field access and what is not. Lua's tag methods are limited. You can't distinguish between table[x] for accessing fields and table.x / table:x for calling methods. The simple solution to your PythonDictionaries problem is to give up using native table syntaxes for element access and rely on methods such as get and set. It will make the implementation much simpler too! --JohnBelmonte

But thats not what Pythons dictionaries look like :-) I know Lua isn't Python. Sol would allow me to do what I want but Lua limits me. I could juggle the code in a number of ways to get it to work without clashes but not how I would like :-( (perhaps some variants should be added...). Thats what I was pointing out above, and the slant of the text is probably pro unified methods :-). You can only go so far in implementing certain objects in Lua. I suppose it kind of overlaps with the table.n problem - tables are multipurpose but have limitations? --NDT

"You can only go so far in implementing certain objects in Lua." I disagree with this. The issue you are having is purely about the syntatic sugar. Lua is not a fancy macro language. On the other hand it is a powerful functional language. Stick with functional interfaces and things work out nicely. --JohnBelmonte

"You can only go so far in implementing certain objects in Lua syntactically" would have been more accurate. Emulating Pythons dictionaries, as close as possible, functionally and syntactically, was just an exercise which had some interesting results. Lua would have no problem emulating the functionality with different syntax/interface. The idea of this page is simply to list some ideas and limitations. --NDT

See also: SampleCode , PythonLists and PythonDictionaries contain class examples.
RecentChanges · preferences
edit · history
Last edited October 23, 2009 7:08 pm GMT (diff)