I wonder if there's a simpler way to call a function or set variable of the same table instead of writing the table name.
For example, Is there a simpler way to call MyClass.test() function from MyClass.setup() in my below example code?
local MyClass = {}
function MyClass.test()
print("Hello")
end
function MyClass.setup()
MyClass.test()
end
MyClass.setup()
If you use : to call the functions instead of ., Lua implicitly inserts a reference to the table itself as the first argument (similar to the this pointer is some object-oriented languages). Then you can say self:test() to get rid of the name dependence.
local MyClass = {
test = function(self)
print("Hello")
end,
setup = function(self)
self:test()
end
}
MyClass:setup()
You can set the module table to be the environment:
local print = print
local _ENV = {}
function test()
print("Hello")
end
function setup()
test()
end
setup()
return _ENV
local MyClass = {}
function MyClass:Setup()
print('hello...Setup')
end
function MyClass:Test()
self:Setup() -- self -> MyClass
print('hello...Test')
end
MyClass:Test()
-- or inherit
local newClass = MyClass
newClass:Test()
local MyClass = {}
function MyClass.test()
print("Hello")
end
function MyClass.setup(self)
self.test()
end
MyClass.setup(MyClass)
the key is self. In the state, MyClass is a obj and create by {}, so you can use MyClass.Test(MyClass) to incoming parameters MyClass to use the func test() of MyClass obj.
ps:
Syntax sugar provided by Luaļ¼
MyClass.setup(MyClass) ==> MyClass:setup()
Related
in the code below, i set up a __call metafunction which, in theory, should allow me to call the table as a function and invoke the constructor, instead of using test.new()
test = {}
function test:new()
self = {}
setmetatable(self, self)
--- private properties
local str = "hello world"
-- public properties
self.__index = self
self.__call = function (cls, ...) print("Constructor called!") return cls.new(...) end
self.__tostring = function() return("__tostring: "..str) end
self.tostring = function() return("self:tstring(): "..str) end
return self
end
local t = test:new()
print(t) -- __tostring overload works
print(tostring(t)) -- again, __tostring working as expected
print(t:tostring()) -- a public call, which works
t = test() -- the __call metamethod should invoke the constructor test:new()
output:
> __tostring: hello world
> __tostring: hello world
> self.tostring(): hello world
> error: attempt to call global `test` (a table value) (x1)
(i'm using metatable(self, self) because i read somewhere it produces less overhead when creating new instances of the class. also it's quite clean-looking. it may also be where i'm getting unstuck).
You're setting the __call metamethod on the wrong table - the self table - rather than the test table. The fix is trivial:
test.__call = function(cls, ...) print("Constructor called!") return cls.new(...) end
setmetatable(test, test)
After this, test(...) will be equivalent to test.new(...).
That said, your current code needs a refactoring / rewrite; you overwrite the implicit self parameter in test:new, build the metatable on each constructor call, and don't even use test as a metatable! I suggest moving methods like tostring to test and setting the metatable of self to a metatable that has __index = test. I'd also suggest separating metatables and tables in general. I'd get rid of upvalue-based private variables for now as they require you to use closures, which practically gets rid of the metatable benefit of not having to duplicate the functions per object. This is how I'd simplify your code:
local test = setmetatable({}, {__call = function (cls, ...) return cls.new(...) end})
local test_metatable = {__index = test}
function test.new()
local self = setmetatable({}, test_metatable)
self._str = "hello world" -- private by convention
return self
end
function test_metatable:__tostring()
return "__tostring: " .. self._str
end
function test:tostring()
return "self:tstring(): " .. self._str
end
If you like, you can merge test and test_metatable; I prefer to keep them separated however.
NativeTable = {
["print"] = {},
["LoadResourceFile"] = {}
}
for k, v in pairs(NativeTable) do
k = function(...)
print("test")
end
end
this would result in defining them in the NativeTable and not as a global function
print = function(...)
print("test")
end
LoadResourceFile = function(...)
print("test")
end
So I'm trying to define a global function with a table name
Guess i could do smth like this
But there must be a better way?
NativeTable = {
["test"] = {},
["LoadResourceFile"] = {}
}
local function OverWriteFunction(FuncName, Func)
local Base = [[ = function(...)
print("jaa")
end
]]
local Final = FuncName .. Base
return Final
end
for k, v in pairs(NativeTable) do
load(OverWriteFunction(k))()
end
In your first example you are redefining the variable k, that is local inside the for loop, so this will not be usable outside the one loop where you define it.
Your second example is something you absolutely should avoid if you can, since defining code inside a string and loading it later means, that even only a syntax error will not be shown on "compiling" it, but only when that exact part is executed. And especially, when you are concatenating string that are meant to be code, you just get the risk of glueing something together wrongly, if you try to have that made generically.
If I understood correctly what you are trying to achieve, I would say, it could be something like this:
NativeTable = {
["test"] = {},
["LoadResourceFile"] = {},
[3] = {}
}
for k, v in pairs(NativeTable) do
if type(k) == "string" then
_G[k] = function(...)
print("output")
end
end
end
test()
LoadResourceFile()
-- _G[3]()
Which outputs:
output
output
What I have done here is to use the _G table which is the global environment of lua, all things you define there with a string in the brackets will be globally available (and what is globally available is inside that table, so be careful, since you can override other functions and variables you have defined!), even when writing it as a normal function call. I did also make sure, to only do this, when the type of k was string, otherwise you could start to define functions that can be called like the last commented out call.
This doesn't make too much sense for me:
NativeTable = {
["print"] = {},
["LoadResourceFile"] = {}
}
for k, v in pairs(NativeTable) do
k = function(...)
print("test")
end
end
First you create a table with table elements print and LoadResourceFile.
Then you iterate over that table and replace the table elements with functions.
Why not simply do this:
myTable = {
a = function() print("I'm function a") end,
b = function() print("I'm function b") end,
}
or
myTable = {}
myTable.a = function () print("I'm function a") end
Then you can call the global function like so: myTable.a()
If you insist on having those functions outside of a table you can simply insert them into the global environment table.
for k, v in pairs(myTable) do _G[k] = v end
then you could call a and b globally. But whatever you're trying to accomplish there's probably a better way than this.
I am trying to write for each lua-resty-redis, lua-resty-memcached and lua-resty-mysql modules a small class that extends the default module. In my child class, I want to call a function from the parent class but couldn't find a proper way no matter what inheritance documentation for Lua I've read.
For example, I want to overwrite the connect() function, do some stuff and call the parent's connect() function at some point. But how?
local redis = require "resty.redis"
function redis.connect(self, ...)
-- Do some stuff here
local ok, err = parent:connect(...)
-- Do some other stuff here
return ok, err
end
How can this be achieved?
As a note, all the above mentioned modules are structured like this:
local _M = { _VERSION = "0.1" }
local mt = { __index = _M }
function _M.new(self)
return setmetatable({ foo = "bar" }, mt)
end
function _M.connect(self, ...)
-- Connect
end
return _M
Thank you in advance!
local redis = require "resty.redis"
local original_connect = redis.connect
function redis.connect(self, ...)
-- Do some stuff here
local ok, err = original_connect(self, ...)
-- Do some other stuff here
return ok, err
end
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.
I'm learning how Lua's metatables work in OOP, and I am confused of the code I read from the object orientation tutorial on lua-users wiki. Could someone helps to explain the following questions? Thanks.
Question 1:
The wiki's explanation: Here we add a metatable to the class table that has the __call metamethod, which is triggered when a value is called like a function. We make it call the class's constructor, so you don't need the .new when creating instances.
(1)How does the __call get called in the example so the constructor is called?
(2)Does "cls" refer to "MyClass?"
setmetatable(MyClass, {
__call = function (cls, ...)
return cls.new(...)
end,
})
Question 2:
What does {} from the following code refer to?
function MyClass.new(init)
local self = setmetatable({}, MyClass)
self.value = init
return self
end
**Here is the Complete code:
local MyClass = {}
MyClass.__index = MyClass
setmetatable(MyClass, {
__call = function (cls, ...)
return cls.new(...)
end,
})
function MyClass.new(init)
local self = setmetatable({}, MyClass)
self.value = init
return self
end
function MyClass:set_value(newval)
self.value = newval
end
function MyClass:get_value()
return self.value
end
local instance = MyClass(5)
-- do stuff with instance...
Question 1:
setmetatable(MyClass, {
__call = function (cls, ...)
return cls.new(...)
end,
})
This sets MyClass's metatable to a table which defines the __call metamethod. Because of that, you can 'call' MyClass (newObj = MyClass(<args>)). In the metamethod, cls refers to the table that is called, in this case it refers to MyClass.
Question 2:
function MyClass.new(init)
local self = setmetatable({}, MyClass)
self.value = init
return self
end
{} is syntax for a table literal, which creates a new table (an empty one in this case). The MyClass table is set as the metatable for a new table. Then this new table is assigned to self.
More about metatables can be found here: https://www.google.com/?gws_rd=ssl#q=lua+metatables as suggested by Anderson Green in the comments.