Scoping classes created in Lua using Luabind - lua

I am aware that Lua classes can be created using the OO system that Luabind exposes to Lua:
http://www.rasterbar.com/products/luabind/docs.html#defining-classes-in-lua
class 'lua_testclass'
function lua_testclass:__init(name)
self.name = name
end
function lua_testclass:print()
print(self.name)
end
a = lua_testclass('example')
a:print()
However I am unable to figure out how to scope the class within another namespace so I can do the following:
a = MyScope.lua_testclass('example')
a:print()
Anyone has a idea. I do not want my classes to pollute the global namespace in Lua.

Luabind's class function will always pollute the global table. However, you can clean up after it:
function newclass(name)
oldglobal = _G[name]
class(name)
cls = _G[name]
_G[name] = oldglobal
return cls
end
Then you would use it like this:
MyScope.lua_testclass = newclass 'lua_testclass'
Analogous to local mod = require 'mod' you have to spell the name of the class twice, but you could easily build another function on top of this that could be used like setclass(MyScope, 'lua_testclass'), automatically putting the class into MyScope:
function setclass(scope, name) scope[name] = newclass(name) end
Disclaimer: All this code is entirely untested.

I did mine a little differently, but it's generally the same concept. Mine doesn't create the class, but rather just moves it. I also implemented it on the C++ side.
To implement what I did in Lua, you would write:
function moveClass(name)
oldGlobal = _G[name]
_G[name] = nil
return oldGlobal
end
To implement it in C++, you would write:
luabind::module(lua) [
luabind::def("moveClass", +[](lua_State * lua, std::string name) {
// In the case the class does not exist, this will just
// remove nil and return nil. That essentially does nothing.
luabind::object oldGlobal = luabind::globals(lua)[name];
luabind::globals(lua)[name] = luabind::nil;
return oldGlobal;
})
];
So now if you were to use that to move a class you created, you would do this:
class 'MyClass'
myTable = {}
myTable.MyClass = moveClass 'MyClass'
As an extra note, if you want the moveClass function to give an error in the case that the class you are trying to move does not exist, use luabind::type(oldGlobal) == LUA_TNIL to determine if the class existed or not.
Example:
luabind::module(lua) [
luabind::def("moveClass", +[](lua_State * lua, std::string name) {
luabind::object oldGlobal = luabind::globals(lua)[name];
if (luabind::type(oldGlobal) == LUA_TNIL) {
throw std::runtime_error("Class does not exist.");
}
luabind::globals(lua)[name] = luabind::nil;
return oldGlobal;
})
];

Related

attempt to call method 'func' (a nil value)

No matter how I approach Lua, I run into this error all the time, so I must not understand something inherit to the language:
attempt to call method 'func' (a nil value)
I've seen the error here a few times as well but the problem doesn't seem clear to me.
Here's my module:
actor.lua
Actor = {
x = 0,
mt = {},
new = function()
local new_actor = {}
new_actor.x = Actor.x
new_actor.mt = Actor.mt
return new_actor
end,
test = function(self, a, b)
print(a, b)
end
}
I'm using Löve.
main.lua
require "game/actor"
local a = Actor:new() --works fine
function love.load()
a.x = 10
print(a.x) --output: 10
a:test(11, 12) --error: attempt to call method 'test' (a nil value)
end
I'm also not sure when it's appropriate to use the previous styling over this in a module.
Actor = {
x = 0
}
Actor.mt = {}
function Actor.new()
print(42)
end
I'm honestly not sure what is more correct than the other but considering I run into a simple error either way, there's probably something I'm missing entirely?
It looks like you're trying to instance a kind of class made of metatables. You basically need to assign new_actor's metatable with Actor.mt. (Resuming the problem: when you're indexing new_actor you're not indexing Actor in this case)
setmetatable(new_actor, Actor.mt);
Even if the metatable is being added, it won't work until you put the meta "__index" event to index a table containing your class methods/values, in this case:
Actor.mt = {
__index = Actor
};
I'd suggest moving your class methods/values into a new table, like Actor.prototype, Actor.fn, etc... avoiding conflicts:
Actor.fn = {
test = function(self, a, b)
print(a, b)
end
};
Actor.mt = {
__index = Actor.fn
};
More about metatables in Lua 5.3 manual.

Inherit a metatable (class) and use its required constructor parameter

I found this tutorial: http://lua-users.org/wiki/InheritanceTutorial
I've got a metatable called Creature. Creature requires an argument in its constructor.
The required argument is a string that represents the name.
local creature = Creature(name)
Creature has a lot of other methods, like getDescription().
Creature's getDescription () returns a string: "This is a creature".
Creature's getName () returns a string: the name
I want to create a new metatable (class) called Player and have it inherit the Creature metatable (class)
The Player class will override only the getDescription () method.
The Player class will also inherit the Creature's getName () method.
Player's getDescription () returns a string: "This is a player".
I want to be able to do the following:
local creature = Creature("Bob")
print(creature:getDescription())
print(creature:getName())
local player = Player("Joey")
print(player:getDescription())
print(player:getName())
Should print:
This is a creature
Bob
This is a player
Joey
Basically, my issue is that the Creature class requires an argument to identify someone, a name. Its getName () function uses the value in the argument and prints it. If I am going to use Player to inherit all of the functions of Creature (and override if necessary), how do I change the code to make sure Player gets the argument it needs?
Code taken from the tutorial:
-- Create a new class that inherits from a base class
--
function inheritsFrom( baseClass )
-- The following lines are equivalent to the SimpleClass example:
-- Create the table and metatable representing the class.
local new_class = {}
local class_mt = { __index = new_class }
-- Note that this function uses class_mt as an upvalue, so every instance
-- of the class will share the same metatable.
--
function new_class:create()
local newinst = {}
setmetatable( newinst, class_mt )
return newinst
end
-- The following is the key to implementing inheritance:
-- The __index member of the new class's metatable references the
-- base class. This implies that all methods of the base class will
-- be exposed to the sub-class, and that the sub-class can override
-- any of these methods.
--
if baseClass then
setmetatable( new_class, { __index = baseClass } )
end
return new_class
end
I want to be able to do the following:
local creature = Creature("Bob")
print(creature:getDescription())
print(creature:getName())
-- ...
Supporting that kind of class usage syntax is certainly possible in lua -- it's just a question of how to use the language mechanisms and tools to achieve that. Some important issues to decide on:
How will object construction happen? What function should the class call to initialize the instance?
What will object instantiation look like from client-code?
How is method overriding accomplished?
From the wiki tutorial, new_class:create() creates a new instance but doesn't call any construction function. So in your OOP system, you'll have to decide on a constructor-like function that the client-code provides and the class creation will call. For example:
function new_class:create(...)
local instance = setmetatable( {}, class_mt )
if new_class.__init__ then new_class.__init__(instance, ...) end
return instance
end
Here I just use __init__ as the constructor name, similar to python, but really any name will work as long as the using code and class creation code agrees.
In order to support object creation syntax like Creature("Bob"), Player("Joey"), you can either make them actual function calls or use the __call metamethod. Using the latter is a simple assignment to __call:
function inheritsFrom( baseClass )
local new_class = setmetatable( {}, { __index = baseClass } )
-- ...
getmetatable(new_class).__call = new_class.create
return new_class
end
For the last question, you override an existing method by just assigning it a new function in the derived class. eg. So to override getDescription in Player you can do:
function Player:getDescription()
return "Is a player"
end
Putting everything together, inheritsFrom
function inheritsFrom( baseClass )
local new_class = setmetatable( {}, { __index = baseClass } )
local class_mt = { __index = new_class }
function new_class:create(...)
local instance = setmetatable( {}, class_mt )
if new_class.__init__ then new_class.__init__(instance, ...) end
return instance
end
getmetatable(new_class).__call = new_class.create
return new_class
end
Defining class Creature + one creature instance:
local Creature = inheritsFrom
{
__init__ = function(self, name) self.name = name end;
getDescription = function(self) return "Is a creature" end;
getName = function(self) return self.name end;
}
local bob = Creature "Bob"
print(bob:getDescription())
print(bob:getName())
Subclassing Player from Creature and overriding getDescription:
local Player = inheritsFrom(Creature)
function Player:getDescription()
return "Is a player"
end
local joey = Player "Joey"
print(joey:getDescription())
print(joey:getName())
As a final remark, the lua Penlight library already implements a class system similar to what I described above but much more featureful and complete. Unless this is an exercise, consider using that instead of reinventing another lua OOP system.

is there aliasing in lua similar to ruby

Can you alias a function (not in a class) in LUA in a similar way to Ruby? In ruby you would do something like this:
alias new_name_for_method method()
def method()
new_name_for_method() # Call original method then do custom code
i = 12 # New code
end
I'm asking because I'm developing for a program that uses LUA scripting and I need to override a function that is declared in a default file.
In Lua, functions are values, treated like any other value (number, string, table, etc.) You can refer to a function value via as many variables as you like.
In your case:
local oldmethod = method
function method(...)
oldmethod(...)
i = 12 -- new code
end
keep in mind that
function method() end
is shorthand for:
method = function() end
function() end just creates a function value, which we assign to the variable method. We could turn around and store that same value in a dozen other variables, or assign a string or number to the method variable. In Lua, variables do not have type, only values do.
More illustration:
print("Hello, World")
donut = print
donut("Hello, World")
t = { foo = { bar = donut } }
t.foo.bar("Hello, World")
assert(t.foo.bar == print) -- same value
FYI, when wrapping a function, if you want its old behavior to be unaffected for now and forever, even if its signature changes, you need to be forward all arguments and return values.
For a pre-hook (new code invoked before the old), this is trivial:
local oldmethod = method
function method(...)
i = 12 -- new code
return oldmethod(...)
end
A post-hook (new code invoked after the old) is a bit more expensive; Lua supports multiple return values and we have to store them all, which requires creating a table:
local oldmethod = method
function method(...)
local return_values = { oldmethod(...) }
i = 12 -- new code
return unpack(return_values)
end
In lua, you can simply override a variable by creating a new function or variable with the same name.
function name_to_override()
print('hi')
end
If you still want to be able to call the old function:
local old_function = name_to_override
function name_to_override()
old_function()
print('hi')
end

Mixin overshadowing

Let's say i have code like this :
class A{ foo() => "A";}
class B{ foo() => "B";}
class C{ foo() => "C";}
class Mix extends A with B,C {
foo() => "MIX";
bar() => super.foo();
}
class MessABC = Object with A,B,C;
class MessBCA = Object with B,C,A;
class MessCAB = Object with C,A,B;
void main() {
Mix mix = new Mix();
MessABC mABC = new MessABC();
MessBCA mBCA = new MessBCA();
MessCAB mCAB = new MessCAB();
print("Mix.foo = ${mix.foo()} Mix.bar = ${mix.bar()} \n"
"mABC.foo = ${mABC.foo()} \n"
"mBCA.foo = ${mBCA.foo()} \n"
"mCAB.foo = ${mCAB.foo()} \n");
}
The output
Mix.foo = MIX Mix.bar = C
mABC.foo = C
mBCA.foo = A
mCAB.foo = B
On the mix object I can call both Mix.foo and C.foo with the super (actually i expected A.foo)
But can i somehow call A.foo and B.foo ?
Also i am a bit confused by the with semantics. A,B,C Looks like "one rank enumeration" but the order is important. And "Dart Editor" doesn't warn me about the name collision. Perhaps i can enable this warning?
To me it feels like something that makes you confused and error-prone.
Mixin application is processed from left to right.
The superclass of Object with A,B,C is Object with A,B, which again has the superclasses Object with A and then Object.
The overriding rules for mixins are the same as for non-mixin superclasses. Your C.foo in Mix overrides the ones inherited from A and B, so Mix.bar's super.foo() only reaches the C.foo, and there is no way to access A.foo or B.foo.
Overriding is perfectly ok, and doesn't cause any warnings, as long as the methods have compatible signatures.
The most thorough description of mixins is still https://www.dartlang.org/articles/mixins/

Lua class objects?

I'm new to Lua and I'm wondering if there's a way to make many class objects to make different items in my case like in a OOP language like C# or Java. An example of what I'm saying is a class like this in Lua...
weapon = {}
function weapon.load()
{
weapon.name = "CHASE'S BUG"
weapon.damage = 1
weapon.rare = "Diet Valley Cheez"
weapon.hottexture = love.graphics.newImage("/ledata/invalid.png")
weapong.playtexture = love.graphics.newImage("/ledata/invalid.png")
weapon.dura = 1
weapon.type = "swing"
}
But in a main class you could make new objects of that class which would be done like so in something like C#
weapon Dagger = new weapon();
Dagger.name = "Dagger of Some Mountain"
...
Is there a way to do that in Lua?
There're many ways. This is a simple one. Not really much OOP, you don't have inheritance and some other stuff. But I think this will work in your case.
function weaponFire ()
print "BANG BANG"
end
function newWeapon (opts)
local weaponInstance = {}
weaponInstance.name = opts.name
weaponInstance.damage = opts.damage
weapon.fire = weaponFire
return weaponInstance
end
Another way to go about it is to use a table like so (using the example of a car):
Car = {}
Car.new = function(miles,gas,health)
local self = {}
self.miles = miles or 0
self.gas = gas or 0
self.health = health or 100
self.repair = function(amt)
self.health = self.health + amt
if self.health > 100 then self.health = 100 end
end
self.damage = function(amt)
self.health = self.health - amt
if self.health < 0 then self.health = 0 end
end
return self
end
It creates a table called 'Car' which would be the equivalent of a class, not an instance, then it defines a method "new" in the Car class which returns an instance of a car with variables and functions. An example to using this implementation:
local myCar = Car.new()
print(myCar.health)
myCar.damage(148)
print(myCar.health)
myCar.repair(42)
print(myCar.health)
Lua is object oriented, but it's not like Java/C++/C#/Ruby, etc, there's no native class, the only way to create new object is to clone an existing object. That's why it's called prototype language(like JavaScript).
Read Programming in Lua Chapter 16. You can mock normal OOP using metatable.
since you tagged with love2d, you may have a look at middleclass. It have docs there. And more it have addon like stateful which is mainly for game and love2d.

Resources