So I am creating a system for Lua, so I can have classes and objects in it. I have the creation of objects down, the problem is creating constructors.
I have constructors like this:
a = MyClass:Create("Hello World!")
The create method has ... as its arguments which it passes on to the constructor method (OnStart). I can read the arguments just fine in the Create method but when OnStart is called the argument somehow ends up being nil instead of "Hello World!"
My code:
Object = { }
function Object:Create(...)
local instance = { }
setmetatable(instance, self)
self.__index = self
instance.Type = Object
-- Now we can call the constructor.
local arg = { ... }
instance.OnStart(table.unpack(arg))
return instance
end
function Object:OnStart(msg)
print(msg)
end
test = Object:Create("Hello World!")
print(test:ToString())
Some how in here the msg argument ends up being nil...
It seems I have found out why it was not working, the slight detail that needs to be changed is one line 9. Instead of instance.OnStart it needs to be instance:OnStart.
Related
hope you having great day , i'm test some stuff with lua, and i got some error
i have this codes in Object.lua
local Object = {name = "Object"}
Object.__index = Object
function Object.new()
local t = setmetatable({}, Object)
return t
end
function Object:keys(table)
local keyset={}
local n=0
for k,v in pairs(table) do
n=n+1
keyset[n]=k
end
return keyset
end
return Object
and i call Object.keys in "Other" script like this
local Object = require("lua.app.common.utils.Object")
local t = {
[1] = a,
[2] = b,
[3]= c
}
Object.keys(t)
and this cause error with
Exception has occurred: bad argument #1 to 'for iterator' (table expected, got nil),
because the parameter 'table' is passed as nil ( i don't know why thuogh debug mode just says its a nil)
on the other hand, if i fix object.keys(table) to object:keys(table), everything works fine, why this error happening?
Declaring the method keys with a colon adds an implicit self parameter as the first argument which requires you to call the method in the same way, using the colon.
Calling the method with the period notation expects you to supply the self parameter but because you only pass in t this is interpreted as self and then nil is added for your table parameter.
Declaring the method with a colon you actually have this
function Object:keys(self, table)
but calling it with the period means you have done this
Object.keys(t, nil)
hence the "table expected, got nil" error
I have this.
components=require("components")
entity={}
--test---
function entity.test(x,y)
self ={}
self.id="test"
--self.position=components.position(x,y)
return self
end
return entity
In main i have this.
entities=require("entity")
function love.load()
test1=entities.test(100,200)
print(test1.id)
end
the output is ok, but, when I add another component .
components=require("components")
entity={}
--test---
function entity.test(x,y)
self ={}
self.id="test"
self.position=components.position(x,y)
return self
end
return entity
and make another print
entities=require("entity")
function love.load()
test1=entities.test(100,200)
print(test1.id)
print(test1.position.y)
end
I got first a nill valur, and then an error because field position is nill. What happen? Thanks in advance.
my component.lua
component = {}
--position--
function component.position(x,y)
self={}
self.x=x
self.y=y
return self
end
return component
You can fix the problem by declaring your variables local, e.g. local self = {}.
When you call entity.test, that function assigns a new table to the global self. It then calls components.position which assigns a whole new table to self, which never gets the position field.
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;
})
];
I'm trying to draw some stuff using wxlua.
ExampleClass = {}
function ExampleClass:New(someWxPanel)
local obj = {}
setmetatable(obj, self)
self.__index = self
self.m_panel = someWxPanel
return obj
end
function ExampleClass:OnPaint()
local dc = wx.wxPaintDC(self.m_panel)
--paint some stuff
end
local example = ExampleClass(somePanel)
somePanel:Connect(wx.wxEVT_PAINT, example.OnPaint)
I get the following error message:
wxLua: Unable to call an unknown method 'm_panels' on a 'wxPaintEvent' type.
While in any other function I define as Example:SomeFunction() self points to my Example instance and I can perfectly access its members here self is a wxPaintEvent?
How did this happen? Does the Connect somehow change self? How can I access my members now?
Appreciate any help!
When you register example.OnPaint as the event handler in somePanel:Connect(wx.wxEVT_PAINT, example.OnPaint), it always gets the event as the first parameter, but your method expects the object (self) passed as the first parameter, hence the error you get. You need to replace the registration with something like this:
somePanel:Connect(wx.wxEVT_PAINT, function(event) example:OnPaint(event) end)
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