Instantiate class from name in MATLAB - oop

I'm trying to list classes I created in some folder in my Matlab folder - using only their name (class name)
as an example, I have a class called 'SimpleString' - and I'm aiming to instantiate an object from that class, if all I know is that its name is 'SimpleString'
So in realtime, I'd like to find out what classes are in a folder (done), then be able to instantiate any of those classes (my question)
Thanks

Use a package to access class constructors with .()-notation.
A Matlab package is simply a folder/directory with a name that begins with +:
+mypackage/foo.m:
classdef foo
methods
function obj = foo(arg1, arg2)
%foo constructor
end
end
end
With class foo defined this way, you can access the constructor of mypackage.foo as
class_name = 'foo';
o = mypackage.(class_name)('arg1_value', 'arg2_value');

Use str2func to get a function handle to the constructor. You can then call it with whatever arguments are appropriate.
>> m = str2func('containers.Map')
m =
#containers.Map
>> x = m({'foo', 'bar'}, {0, 1})
x =
containers.Map handle
Package: containers
Properties:
Count: 2
KeyType: 'char'
ValueType: 'double'
Methods, Events, Superclasses

You can use the WHAT function to discover classes (as well as functions,packages,etc...) in a certain folder, then call METHODS to find the signature of the constructor of the class (some parsing needed here), finally using FEVAL (passing arguments if any) to create an object from this class.
You could also use meta.class to get all sorts of meta-information about your classes.
EDIT
Here is some code to illustrate what I had in mind:
%# folder containing your classes
pathName = fullfile(pwd,'folder');
%# make sure it is on the path
p = textscan(path, '%s', 'Delimiter',';'); p=p{1};
if ~any(ismember(p,pathName))
addpath(pathName)
end
%# list MATLAB files
w = what(pathName);
%# get class names
fNames = cellfun(#(s) s(1:end-2), w.m, 'Uni',false); %# remove .m extension
fNames = [fNames ; w.classes]; %# add classes in #-folders
%# get classes metadata
mt = cellfun(#meta.class.fromName, fNames, 'Uni',false); %# get meta-data
mt = mt( ~cellfun(#isempty,mt) ); %# get rid of plain functions
%# build object from each class
objects = cell(numel(mt),1);
for i=1:numel(mt)
%# get contructor function
ctorMT = findobj(mt{i}.MethodList, 'Access','public', 'Name',mt{i}.Name);
%# get number of contructor arguments
numArgs = numel(ctorMT.InputNames);
%# create list of arguments (using just zeros)
args = repmat({0}, [numArgs 1]);
%# create object
try
obj = feval(ctorMT.Name,args{:});
catch ME
warning(ME.identifier, ME.message)
obj = [];
end
%# store object
objects{i} = obj;
end
As you can see, I found it easier to simply use meta.class to get metadata about the classes, instead of manually parsing the output of methods('fcn','-full') as I originally suggested.
However this is not perfect, as there is no way to find out what type of input each constructor expect (only how many). I opted to always pass 0 for each argument..
To test the implementation above, I create these sample classes (one in a self-contained file, the other defined in #-folder with multiple files):
folder/hello.m
classdef hello
properties
name = '';
end
methods
function this = hello()
this.name = 'world';
end
function val = get.name(obj)
val = obj.name;
end
function obj = set.name(obj,val)
obj.name = val;
end
function say(obj)
fprintf('Hello %s!\n',obj.name);
end
end
end
folder/#hello2/hello2.m
classdef hello2
properties
name
end
methods
function this = hello2(val)
this.name = val;
end
function val = get.name(obj)
val = obj.name;
end
function obj = set.name(obj,val)
obj.name = val;
end
end
methods
say(obj)
end
end
folder/#hello2/say.m
function say(obj)
fprintf('Hello2 %s!\n', obj.name);
end

You can use eval to instantiate the class using just the class name.
instance = eval('SimpleString');
However, if you're simply iterating through all the m-files in a folder containing class definitions and grabbing the file names, you'll only be able to invoke the default constructor using this method.

Related

Entities inheriting Entity.lua variables, but not its methods

I am building a game with enemies and players, all of which are set up to have various states for animation and behavior. The parent class for both is Entity.lua, from which they inherit variables and methods. However, while both enemies and players are inheriting the variables, for some reason the enemies do not inherit the methods. So, if I try to call snakey:changeState('search'), for example, it gives me an error message "Attempt to call method 'changeState' (a nil value)".
I have used the same sequence for creating entities in several games in the past and never had this problem. In fact, if I create the Player in the same way, file and location as the enemies, I receive no error messages.
Here is the code where I create the entities.
local snakey
snakey = Snakey {
platform = platform,
player1 = self.player1,
player2 = self.player2,
stateMachine = StateMachine {
['search'] = function() return SnakeySearchState(snakey) end,
['chasing'] = function() return SnakeyChasingState(snakey) end,
['idle'] = function() return SnakeyIdleState(snakey) end
}
}
-- snakey:changeState('search')
-- snakey.stateMachine:change('search', params)
table.insert(self.entities, snakey)
The two coded out lines are where I noticed the problem. The first line gives and error and the second does work, but is not satisfactory because it is a work-around.
Here is the code for Entity.lua: I don't include details of the functions for brevity, but all are working properly for when player calls them.
Entity = Class{}
function Entity:init(def)
-- position
self.x = def.x
self.y = def.y
self.gravity = 6
-- many more variables
end
function Entity:changeState(state, params)
self.stateMachine:change(state)
end
function Entity:update(dt)
self.stateMachine:update(dt)
end
function Entity:collides(entity)
-- do something
end
function Entity:onDamage()
-- do something
end
function Entity:render()
- renders sprite
end
Player code (in brief)
Player = Class{__includes = Entity}
function Player:init(def)
Entity.init(self, def)
-- more variables
end
function Player:update(dt)
Entity.update(self, dt)
end
function Player:render()
Entity.render(self)
end
And perhaps the trouble spot, one one enemy's script
Snakey = Class{__includes = Entity}
function Snakey:init(def)
Entity.init(self, def)
-- yet more variables
end
function Snakey:update(dt)
Entity.update(self, dt)
-- entity behavior (works fine, so omitted)
end
function Snakey:render()
Entity.render(self)
end
Thank you very much for your help. I'm feeling quite frustrated because this sequence has worked in the past and I would really like to know why it's not calling those Entity methods.
Adding the class library
--Copyright (c) 2010-2013 Matthias Richter
local function include_helper(to, from, seen)
if from == nil then
return to
elseif type(from) ~= 'table' then
return from
elseif seen[from] then
return seen[from]
end
seen[from] = to
for k,v in pairs(from) do
k = include_helper({}, k, seen) -- keys might also be tables
if to[k] == nil then
to[k] = include_helper({}, v, seen)
end
end
return to
end
-- deeply copies `other' into `class'. keys in `other' that are already
-- defined in `class' are omitted
local function include(class, other)
return include_helper(class, other, {})
end
-- returns a deep copy of `other'
local function clone(other)
return setmetatable(include({}, other), getmetatable(other))
end
local function new(class)
-- mixins
class = class or {} -- class can be nil
local inc = class.__includes or {}
if getmetatable(inc) then inc = {inc} end
for _, other in ipairs(inc) do
if type(other) == "string" then
other = _G[other]
end
include(class, other)
end
-- class implementation
class.__index = class
class.init = class.init or class[1] or function() end
class.include = class.include or include
class.clone = class.clone or clone
-- constructor call
return setmetatable(class, {__call = function(c, ...)
local o = setmetatable({}, c)
o:init(...)
return o
end})
end
-- interface for cross class-system compatibility (see https://github.com/bartbes/Class-Commons).
if class_commons ~= false and not common then
common = {}
function common.class(name, prototype, parent)
return new{__includes = {prototype, parent}}
end
function common.instance(class, ...)
return class(...)
end
end
-- the module
return setmetatable({new = new, include = include, clone = clone},
{__call = function(_,...) return new(...) end})
It turns out that sequence matters. In trying to create the minimum reproducible code I could not reproduce the error. After some searching (and a little frustration), I noticed that in Dependencies.lua I was requiring the enemies BEFORE Entity.lua, but Player.lua was required after. I would have thought this wouldn't matter, since everything was imported into the program on frame 1 and I was creating entities on something like frame 1000, but alas. Anyway, problem solved! Always require parent classes before child classes... Lesson learned. :)

OOP in Lua - Creating a class?

I'm aware there are a few questions about implementing OOP in Lua on this site, however, this one is a bit different (at least compared to what I found).
I'm trying to create a class called "human", and make it so objects created with the "new" constructor of "human", inherit everything inside human except it's constructor. However, I also don't want to be able to use methods inside of human, on human. So whatever's inside the human class, is only passed to created objects. Here's an example:
-- "Human" class
human = {}
function human.new(name)
local new = {} -- New object
-- Metatable associated with the new object
local newMeta =
{
__index = function(t, k)
local v = human[k] -- Get the value from human
print("Key: ", k)
if type(v) == "function" then -- Takes care of methods
return function(_, ...)
return v(new, ...)
end
else
return v -- Otherwise return the value as it is
end
end
}
-- Defaults
new.Name = name
new.Age = 1
return setmetatable(new, newMeta)
end
-- Methods
function human:printName()
print(self.Name)
end
function human:setAge(new)
self.Age = new
end
-- Create new human called "bob"
-- This works as expected
local bob = human.new("Bob")
print(bob.Name) -- prints 'Bob'
bob:printName() -- prints 'Bob'
bob:setAge(10) -- sets the age to 10
print(bob.Age) -- prints '10'
-- But I don't want something like this allowed:
local other = bob.new("Mike") -- I don't want the constructor passed
-- I'd also like to prevent this from being allowed, for "human" is a class, not an object.
human:printName()
So creating the object with human.new("Bob") works fine, but it also passes the constructor, and I can still use the object methods on the class. I'm very new to the concept of OOP, so I'm sorry if this was a horrible question. But if anyone could help, I'd appreciate that.
I have run into the same issue before. You need two tables. One for object methods and one for class methods. Set the metatable of constructed objects to the object method table. For example:
local Class = {}
local Object = {}
Object.__index = Object
function Class.new()
return setmetatable({}, Object)
end
setmetatable(Class, {__call = Class.new})
function Object.do()
...
end
return Class
And use it
Class = require('Class')
local obj = Class.new() -- this is valid
obj.do() -- this is valid
obj.new() -- this is invalid
Class.do() -- this is invalid

Function returns nil when called inside constructor

I just started programming in lua and I created sort of oop structure following this tutorial: http://tylerneylon.com/a/learn-lua/
Problem is, when I created function that returns object or table of objects and call it inside constructor, it returns nil.
Here is my code for first object:
require "ObjectB"
ObjectA = {}
function ObjectA:new(num)
newInstance = {}
newInstance.var = self:foo(num)
self.__index = self
return setmetatable(newInstance, self)
end
function ObjectA:foo(num)
return ObjectB:new(num)
end
, and for second object:
ObjectB = {}
function ObjectB:new(num)
newInstance = {}
newInstance.num = num
self.__index = self
return setmetatable(newInstance, self)
end
When I do this:
myObject = ObjectA:new(5)
print(myObject.var.num)
, I get error: "Error: main.lua:14: attempt to index field 'var' (a nil value)".
But when I do this:
myObject = ObjectA:new(5)
myObject.var = ObjectA:foo(5) //setting var by calling foo outside of constructor
print(myObject.var.num)
, everything seems to work fine and print result is really 5. Can anyone tell me what is reason for this strange behaviour or what am I doing wrong here?
Variables are global by default, so the two variables newInstance in ObjectA:new and ObjectB:new are the same global variables, you assign it a new value, the previous value is gone.
Instead, use local variables like this:
function ObjectA:new(num)
local newInstance = {}
--the rest
end
and
function ObjectB:new(num)
local newInstance = {}
--the rest
end

Extending MATLAB uicontrol

I'd like to customize some of the MATLAB uicontrols (such as the drop-down box) to give them more user-friendly functionality.
My question is: Is it possible to extend/inherit the uicontrol? If so, how do you do it? If not, is there a workaround?
I have tried this basic code just to get it setup, but I receive the following error:
The specified super-class 'uicontrol' contains a parse error or cannot be found on
MATLAB's search path, possibly shadowed by another file with the same name.
classdef ComboBox < uicontrol
methods(Access = public)
function obj = ComboBox()
set(obj, 'Style', 'popup');
end
end
end
The error occurs when I try to add it to a figure:
cmb = ComboBox();
set(cmb, 'Parent', obj.ui_figure);
Edit: After thinking about it, I think this would be a decent workaround, however, I'd still like to know how to extend uicontrol if it's possible.
classdef ComboBox < uicontrol
properties(Access = public)
Control;
end
methods(Access = public)
function obj = ComboBox(parent, items)
obj.Control = uicontrol();
set(obj.Control, 'Style', 'popup');
set(obj.Control, 'Parent', parent);
set(obj.Control, 'String', items);
end
end
end
There is no documented way (as of R2013a) to write subclasses to MATLAB Handle Graphics
classes. In fact, because of the way MATLAB stores the hg objects, we can't even get
the class of an hg object easily. For example:
>> fig = figure();
>> class(f)
ans =
double
>> isa(f, 'figure')
ans =
0
>> ishghandle(f)
ans =
1
One solution to this is to write a class which subclasses either handle, or
hgsetget, and keeps a handle to a uicontrol object as a private property.
For example:
classdef ComboBox < hgsetget
properties (Access = private)
Control
end
properties
% extend the functionality of your new uicontrol with additional
% properties
newProp1
newProp2
end
properties (Dependent = true)
% make any properties of uicontrol for which you want to still
% allow access as dependent properties. define set and get methods
% for these properties below
fontSize
foregroundColor
backgroundColor
items
end
methods
function obj = ComboBox(parent, items)
obj.Control = uicontrol(parent, 'Style', 'popup', ...
'String', items);
% make sure to delete this object if you delete the uicontrol
set(obj.Control, 'DeleteFcn', {#(source, eventData)delete(obj)})
end
% Define set and get methods for your new properties. These methods
% will set the actual properties, and then modify the uicontrol in
% some way
function prop = get.newProp1(obj)
prop = obj.newProp1;
end
function set.newProp1(obj, newVal)
obj.newProp1 = newVal;
% do something else
end
function prop = get.newProp2(obj)
prop = obj.newProp2;
end
function set.newProp2(obj, newVal)
obj.newProp2 = newVal;
% do something else
end
% Define set and get methods for any uicontrol properties you wish
% to retain. These methods will simply redirect calls to the
% uicontrol object.
function size = get.fontSize(obj)
size = get(obj.Control, 'FontSize');
end
function set.fontSize(obj, newSize)
set(obj.Control, 'FontSize', newSize);
end
function color = get.backgroundColor(obj)
color = get(obj.Control, 'BackgroundColor');
end
function set.backgroundColor(obj, newColor)
set(obj.Control, 'BackgroundColor', newColor);
end
function color = get.foregroundColor(obj)
color = get(obj.Control, 'ForegroundColor');
end
function set.foregroundColor(obj, newColor)
set(obj.Control, 'ForegroundColor', newColor);
end
% You can even rename some uicontrol properties to fit your
% purpose.
function items = get.items(obj)
items = get(obj.Control, 'String');
end
function set.items(obj, newItems)
set(obj.Control, 'String', newItems);
end
end
end
You can then use the ComboBox as you would any other uicontrol handle:
obj = ComboBox(figure, 'hello|goodbye');
set(obj, 'items', 'newItem1|newItem2');
There are undocumented ways of extending handle graphics classes,
but I'm not familiar with them. Check out this reference:
http://undocumentedmatlab.com/blog/introduction-to-udd/

Lua class inheritance problem

I have two classes in Lua. One inherits another.
test1 = {test1Data = 123, id= {0,3}}
function test1:hello()
print 'HELLO!'
end
function test1:new (inp)
inp = inp or {}
setmetatable(inp, self)
self.__index = self
return inp
end
test2 = {}
function test2:bye ()
print ('BYE!', self.id)
end
function test2:new_inst_test (baseClass, inp)
inp = inp or {}
setmetatable(inp, self)
self.__index = self
if baseClass then
setmetatable( inp, { __index = baseClass } )
end
return inp
end
a = test1:new({passData='abc1'})
b = test1:new({passData='ghyrty'})
c = test2:new_inst_test(a,{temp = '123343321135'})
d = test2:new_inst_test(b, {temp = '1'})
print (c.temp, c.test1Data, c.passData)
print (d.temp, d.test1Data, d.passData)
c:bye()
c:hello()
I want test2 not just inherit test1, but save own methods ('bye').
Is it possible?
Thanks!
you should set a metatable with __index=baseclass on the class metatable I think. But that will change the metatable for all objects in the test2 class. Doing it this way, you will use the methods from the class itself, and only use methods from the parent when the method does not exists in the current class, or it's metatable.
So it should be like
if baseClass then
setmetatable( self, { __index = baseClass } )
end
On the other hand it's kind of weird that you only specify the baseclass when making a new instance, instead of specifying it when creating the new class.
So I'd rethink how you inherit between classes instead of between instances and classes.
As a small wizardry themed example:
--oop.lua Example of OOP and inheritance in Lua
Person={
age=0,
className='Person'
}
-- needed if needed add comparisons, operations, ...
mtPerson={}
mtPerson.__index={
getClassName=function(self)
return self.className
end,
new=function(self,t)
return setmetatable(t or {},{__index=self})
end,
inherit=function (self,t,methods)
-- This is the heart of the inheritance: It says:
-- Look it up in the methods table, and if it's not there, look it up in the parrent class (her called self)
-- You pass this function the parent class (with :), a table of attributes and a table of methods.
local mtnew={__index=setmetatable(methods,{__index=self})}
return setmetatable(t or {},mtnew)
end,
introduce=function(self)
print(("Hi! I'm %s, I'm a %s and I'm %d years old"):format(self.instanceName,self.className,self.age))
end
}
setmetatable(Person,mtPerson)
-- Wizard inherits from the class Person, and adds some default values and methods
Wizard=Person:inherit({
className="Wizard",
knownSpells={},
},
{
listSpells=function(self)
print("known spells:",self)
if #self.knownSpells==0 then
print'none'
else
for k,v in ipairs(self.knownSpells) do
print(k,v)
end
end
end
}
)
i1=Person:new{
inventory={'wallet'},
instanceName="John",
}
i2=Wizard:new{ -- inherited method "new"
inventory={'wallet','wand','cloak of invisibility'},
instanceName="Harry",
age=20,
knownSpells={'Avada kavedra', 'Sesame open'}
}
i1:introduce() -- inherited method "introduce" notice that qge is the default value of 0
i2:introduce() --
i2:listSpells() -- method only in class 2
i1.age=26
i1:introduce() -- changed age of instance
print(Person.age) -- didn't change class defaults
print(Wizard.age)
i1:listSpells() -- Error.
While writing this, I came tho the conclusion that OOP in Lua is at the same time very simple, and very complicated. You simply have to really think things through before writing code, and stick with the plan afterwards. As such, here I chose to put attributes in the class and instance tables themselves, and put all methods in their respective metatables. I did this because now it's easy to iterate through all attributes, without encountering methods, but any choice that works is valid. You just have to pick one.