Metatable in Module Script not excetuting Roblox - oop

so i made 2 module scripts
here's the code:
local base = {}
base.__index = base
base.Number = 5
function base:New()
local t = setmetatable({}, self)
t.__index = t
return t
end
return base
second:
local base = script.Parent.Base
local child = require(base):New()
return child
this one is normal script:
local child = require(script.Parent.Child1)
print(child.Number)
and i get this message after i try executing it
stack begin
script
'ServerScriptService.Script', Line 1
Stack End
it should've executed "5"
but its not working and i don't know why

In your Base class, you set the __index metamethod to the base object, then in the constructor you say setmetatable({}, base) these two lines mean that when someone asks for a property on the empty table, that it should be found on the base object instead. But they you overwrite that behavior by setting the __index metamethod again. This removes the relationship between the new object and its base class.
So to fix this, just remove that line in the constructor.
function base:New()
local t = setmetatable({}, base)
return t
end

Related

bad argument #2 to 'setmetatable' (nil or table expected)?

I currently stuck on this with a corona app I'm creating.
I have a file structure like below:
App -> Classes -> Objects -> Ships
In the App folder is the main.lua, menu.lua, level.lua and Class.lua. In the Classes folder there is Object.lua. In Objects, ship.lua and finally in the Ships are my different ships i.e. player and enemy.
I followed this tutorial and my code is almost completely identical to his (bar player and enemys classes), but still am receiving this error in the Class.lua is
"bad argument #2 to 'setetatable'(nil or table expected)"
The code I receive the error on is
function Class(Super)
Super = Super or Base
local prototype = setmetatable({}, Super) -- receive error here
prototype.class = prototype
prototype.super = Super
prototype.__index = prototype
return prototype
end
Base = Class()
function Base:new(...)
local instance = setmetatable({}, self)
instance:initialize(...)
return instance
end
function Base:initialize() end
function Base:get()
local Instances = self.Instances
if (not Instances[1]) then local obj = self:new() end
return table.remove(Instances, 1)
end
function Base:dispose()
table.insert(self.Instances, self)
end
I've tried changing the classes and changing the "setmetatable({},Super)" to "setmetatable(Super, self), putting all the classes in one file, I've read the lua docs, requiring the Class.lua in the mai, menu and the level.lua etc. and nothing has worked.
Any help would be greatly appreciated.
Thanks
function Class(Super)
Super = Super or Base
local prototype = setmetatable({}, Super) -- receive error here
prototype.class = prototype
prototype.super = Super
prototype.__index = prototype
return prototype
end
Base = Class()
Follow the execution of the code above.
You declare a function Class and then call it (and assign its returned value to Base).
Step through the execution of Class from the Base = Class() line.
function Class(Super)
The function takes one argument named Super
Super = Super or Base
You are allowing the Super argument to be nil/unpassed by using a default value of Base.
This call Base = Class() is not passing a value so this line Super = Super or Base has Super as nil and so evaluates to Super = nil or Base however the global Base is also nil as it has not yet been assigned to so you get Super = nil.
local prototype = setmetatable({}, Super)
This line then attempts to use Super (assigned from the line before) only it is, as we just saw, nil hence your error.
The bit from the tutorial that you missed (or at least missed in your posted snippet) is the crucially important local Base line above the Class function definition.

Lua & OO, how to access method from another method?

So if I have an Object and needs to call one method from another within that Object, how do I construct that call?
TestObject = {}
TestObject.__index = TestObject
function TestObject.new()
local self = setmetatable({}, TestObject)
self.value = init
-- a count [integer] of something. Not important what
self.counter = 99
return self
end
function TestObject:getCount()
return self.counter
end
function TestObject:getCountPlus(add_value)
-- HERE HOW SHOULD THIS BE FORMATED??
return self.getCount() + add_value
end
And using this Object would be something like this:
local testObject = TestObject.new()
testObject:getCountPlus(1)
which should result in 100.
The getCount() needs to know what instance it is in. When you write
function TestObject:getCount()
it is same as writing
function TestObject.getCount(self)
(note the colon changed to dot). So calling self.getCount() is like calling getCount with self=nil. Do self:getCount(), which is same as self.getCount(self). This may seem odd: why does interpreter not provide self automatically? It's just the way the language was designed: it only provides self automatically with the : notation.

Avoiding duplicating data when using SuperClass

I am developing a MATLAB OOP project for the first time. My parent class will have a very large matrix which the children(many) need to access. How can I prevent the children from duplicating the data ?
In pseudo code I require that,
classdef parent
properties
largeMatrix;
end
end
classdef child < parent
methods
function obj = child(parent)
Data.parent of this child = Share from parent
end
...
something = largeMatrix(n,m);
end
end
p = parent; p.largeMatrix = rand(100);
c1 = child(p);
c2 = child(p);
Both children c1 and c2 should access same data created in the original rand(100), but should not be copying the largeMatrix as I need many children, and would like the program to be memory efficient. The largeMatrix will be read from a file.
PS: This is the first time I am posting in this forum, so do forgive me if I have posted it wrongly.
MATLAB copies the array on write.
Suppose that your parent class is (no need to subclass a handle):
classdef parent
properties
largeMatrix;
end
end
and your child class is:
classdef child < parent
methods
function obj = child(parent)
obj.largeMatrix = parent.largeMatrix;
end
end
end
Now, let's create parent and assign a large matrix to its property largeMatrix:
p = parent;
p.largeMatrix = rand(1e4); % 750 MB circa
Check out the jump in the memory:
Now, let's create a child and check that the data was referenced:
c = child(p);
size(c.largeMatrix)
As you can see no jump in the memory:
Finally, let's make a simple change in the child's data:
c.largeMatrix(1) = 1;
As you can see, only on write the array is effectively copied:
To prevent writes on child.largeMatrix define the property in the parent class with attribute (Abstract = true) and in the child (SetAccess = immutable).
A class is just a data type, it does not hold any data. If you instantiate an object parent of the Parent class, and then an object child of the Child class, then by default child will not inherit any data from parent. You can copy the data from one object to another by using a copy constructor.
child = parent; % this copies the data in `parent` to `child`
However, in this case Matlab creates a copy of the data in parent.
You can avoid copying the data by using handle objects. You can assign the handle object to multiple variables or pass it to functions without causing MATLAB to make a copy of the original object. For example,
classdef A < handle
properties
largeMatrix; % wrap your large data into a handle class
end
end
classdef B
properties
data;
end
methods
function obj = B(mydata)
obj.data = mydata;
end
end
end
Then in the main program you can assign
a = A();
a.largeMatrix = rand(100);
b1 = B(a);
b2 = B(a);
b3 = b1; % can even do this
% no copies of largeMatrix were made, because `a` is a handle object
% accessing largeMatrix
b1.data.largeMatrix
b3.data.largeMatrix

How to clear a persistent variable in a MATLAB method

I have a MATLAB class that contains a method that employs a persistent variable. When certain conditions are met I need to clear the persistent variable without clearing the object to which the method belongs. I've been able to do this, but only by employing clear functions which has excessively broad scope for my purposes.
The classdef .m file for this problem:
classdef testMe
properties
keepMe
end
methods
function obj = hasPersistent(obj)
persistent foo
if isempty(foo)
foo = 1;
disp(['set foo: ' num2str(foo)]);
return
end
foo = foo + 1;
disp(['increment foo: ' num2str(foo)]);
end
function obj = resetFoo(obj)
%%%%%%%%%%%%%%%%%%%%%%%%%
% this is unacceptably broad
clear functions
%%%%%%%%%%%%%%%%%%%%%%%%%
obj = obj.hasPersistent;
end
end
end
A script that employs this class:
test = testMe();
test.keepMe = 'Don''t clear me bro';
test = test.hasPersistent;
test = test.hasPersistent;
test = test.hasPersistent;
%% Need to clear the persistent variable foo without clearing test.keepMe
test = test.resetFoo;
%%
test = test.hasPersistent;
test
The output from this is:
>> testFooClear
set foo: 1
increment foo: 2
increment foo: 3
increment foo: 4
set foo: 1
test =
testMe
Properties:
keepMe: 'Don't clear me bro'
Methods
which is the desired output. The problem is that the line clear functions in the classdef file clears all functions in memory. I need a way to clear with a much smaller scope. For example, if hasPersistent' was a function instead of a method, the appropriately scoped clear statement would beclear hasPersistent`.
I know that clear obj.hasPersistent and clear testMe.hasPersistent both fail to clear the persistent variable. clear obj is similarly a bad idea.
Following the discussion in the comments, I think you want to use make foo a private property, accompanied with appropriate increment/reset public functions.
You definitely don't need a persistent variable to implement what you want. But, in any case, to remove a persistent variable from a class method you have to clear the corresponding class. In your case, clear testMe should do what you want.
A related issue is how to clear a persistent variable in a package function. To remove persistent variable myVar from function foo within package foo_pkg you have to do this:
clear +foo_pkg/foo
This should work as long as the parent folder of folder +foo_pkg is in the MATLAB path.

Can properties of an object handle returned from a function be used without first assigning to a temporary variable?

I have a function that returns a handle to an instantiated object. Something like:
function handle = GetHandle()
handle = SomeHandleClass();
end
I would like to be able to use the return value like I would if I was writing a program in C:
foo = GetHandle().property;
However, I get an error from MATLAB when it tries to parse that:
??? Undefined variable "GetHandle" or class "GetHandle".
The only way I can get this to work without an error is to use a temporary variable as an intermediate step:
handle = GetHandle();
foo = handle.property;
Is there a simple and elegant solution to this, or is this simply impossible with MATLAB's syntax?
To define static properties, you can use the CONSTANT keyword (thanks, #Nzbuu)
Here's one example from MathWorks (with some errors fixed):
classdef NamedConst
properties (Constant)
R = pi/180;
D = 1/NamedConst.R;
AccCode = '0145968740001110202NPQ';
RN = rand(5);
end
end
Constant properties are accessed as className.propertyName, e.g. NamedConst.R. The values of the properties are set whenever the class is loaded for the first time (after the start of Matlab, or after clear classes). Thus, NamedConst.RN will remain constant throughout a session as long as you don't call clear classes.
Hmm, I don't like to disagree with Jonas and his 21.7k points, but I think you can do this using the hgsetget handle class instead of the normal handle class, and then using the get function.
function handle = GetHandle()
handle = employee();
end
classdef employee < hgsetget
properties
Name = ''
end
methods
function e = employee()
e.Name = 'Ghaul';
end
end
end
Then you can use the get function to get the property:
foo = get(GetHandle,'Name')
foo =
Ghaul
EDIT: It is not excactly like C, but pretty close.
The only way to have a static property in MATLAB is as a constant:
classdef someHandleClass < handle
properties (Constant)
myProperty = 3
end
end
then someHandleClass.myProperty will return 3.