I'm learning about MATLAB classes they certainly seem different to what I'm used to. Below is an example class I'm using.
I initialise my class with the line below,
myClass = ClassTest(3);
This is fine. The issue I have is calling the RunMain function.
First call
myClass.RunMain(myClass)
I get the error message too many inputs.
Second call
myClass.RunMain(myClass, anything)
This call works. However, I find it strange I need to supply a second parameter which is never used - just seem messy. Sure I'm missing something here.
classdef ClassTest < handle
properties
myNum;
myDate = datenum(date);
end
methods
function ct = ClassTest(someNum)
ct.myNum = someNum;
end
% this function does not work when called
%function RunMain(obj)
% obj.myNum = obj.myNum * 2;
% disp(obj.myNum);
%end
% this works
function RunMain(obj, anything)
obj.myNum = obj.myNum * 2;
disp(obj.myNum);
end
end
Update
I can see when I debug that the anything parameter is exactly the same as obj even obj.myNum has changed value.
Correct syntax for calling a method where myClass is an object of the class defining the method RunMain is:
In case of function RunMain(obj) it is one of these:
myClass.RunMain()
RunMain(myClass)
In case of function RunMain(obj, anything) it is one of these:
myClass.RunMain(anything)
RunMain(myClass, anything)
You can find more details regarding syntax here:
http://de.mathworks.com/help/matlab/matlab_oop/ordinary-methods.html
Related
I am having some trouble with matlab. I am working with b-splines. Sometimes I want to work with the actual spline, while other times I only want to use the so-called basis functions. Without diving into the theory of b-splines, the practical difference is that the when I want to work with the b-spline, I need an extra method and property. I want this property to be initialized by passing it in the constructor.
What I have so far (with most irrelevant methods and properties removed) hopefully roughly demonstrates the behavior that I want:
bsplinespace.m:
classdef bsplinespace < handle
properties
p % polynomial degree
end
methods
function result = bsplinespace(p)
result.p = p;
end
end
end
bspline.m:
classdef bspline < bsplinespace
properties
controlpoints
end
methods
function result = bspline(p, controlpoints)
result.controlpoints = controlpoints;
end
function result = getp(this)
result = this.p;
end
end
end
However, in this scenario the bspline constructor calls the bsplinespace constructor without passing any arguments, causing it to crash:
Not enough input arguments.
Error in bsplinespace (line 8)
result.p = p;
Error in bspline (line 7)
function result = bspline(p, controlpoints)
To be more explicit, what I want is:
One class bsplinespace, which has a constructor which accepts one parameter p
A class bspline, which is the same, but has an extra property and method
Is there an elegant way to implement this?
In your constructor method for bspline, you need to explicitly call the superclass constructor with input argument p:
function result = bspline(p, controlpoints)
result#bsplinespace(p)
result.controlpoints = controlpoints;
end
Otherwise MATLAB will call the superclass constructor with zero input arguments, and you'll get the error you're seeing.
It's a perfectly sensible design, and allows you to control the details of how arguments to the subclass constructor are passed through to the superclass constructor (or not, if you'd like to provide default arguments instead).
We have this code in 'Reconstruction the subclass object from a saved struct' from MATLAB OOP documentation.
classdef MySuper
% Superclass definition
properties
X
Y
end
methods
function S = saveobj(obj)
% Save property values in struct
% Return struct for save function to write to MAT-file
S.PointX = obj.X;
S.PointY = obj.Y;
end
function obj = reload(obj,S)
% Method used to assign values from struct to properties
% Called by loadobj and subclass
obj.X = S.PointX;
obj.Y = S.PointY;
end
end
methods (Static)
function obj = loadobj(S)
% Constructs a MySuper object
% loadobj used when a superclass object is saved directly
% Calls reload to assign property values retrived from struct
% loadobj must be Static so it can be called without object
obj = MySuper;
obj = reload(obj,S);
end
end
end
I have a question about obj = MySuper. What is purpose of this line? How we can call MySuper object from this function without insert any object to loadobj function?
You first question is: What is the purpose of the obj = MySuper; line?
The answer is that the obj = MySuper; line initiates the variable obj as an element of the class MySuper. Non-static functions in a class will only run if the first input parameter is an instance of the class, so if obj is not initiated as a MySuper-object, then matlab will look for other functions called reload to run, and if none is found give you an error.
For your second question, I am not 100% sure what you mean. But I hope one of the following points will answer your question:
If you want to make a function that relates to a class, but not to a specific instance of the class, you can make a static function, these can take any input (also (if you want it that way) no input at all) - that is they don't need to have a first input parameter of the specific class.
To run a static function, use the class name followed by a dot and then the function name, so here you would type MySuper.loadobj(S) to run the function with the parameter S.
I would suggest that you try this out with the given example to better get to know the way oop works in matlab, you may for example try:
S.PointX = 1;
S.PointY = 2;
obj = MySuper.loadobj(S)
I hope this answers your questions.
I have the following scenario. In myClass.m I have defined
classdef myClass
...
methods
function y = foo(this, x)
...
end
end
end
Then I execute
obj = myClass();
nargin(#obj.foo)
and get as a result -1 while I would expect 1. The function nonetheless accepts only one argument.
I actually want to pass the handle to another function (in which I don't have access) which checks the number of arguments and I want the check nargin(f)==1 to succeed. Is there a way to do that?
PS
I know that if I define the method as static I will get the correct result by calling nargin(#(x)Test.foo) but the method accesses class variables.
Even though this question got answered and accepted, I think it is worth to show a working approach, which works even without creating an instance of the class. Reference to metaclass: https://ch.mathworks.com/help/matlab/ref/metaclass.html
metaClass = ?myClass
numArgIn = zeros(length(metaClass.MethodList), 1);
names = strings(length(metaClass.MethodList), 1);
for i=1:length(metaClass.MethodList)
names(i) = string(metaClass.MethodList(i).Name);
numArgIn(i) = numel(metaClass.MethodList(i).InputNames);
end
disp(numArgIn(names=="foo"))
When you create a folder with the class and some modules, you can use the following one-liner notation:
nargin('#myClass/foo.m')
In the latter example, the file ending can be removed without effect.
I can no longer verify the validity of this answer. See more recent answer(s) and comments.
Original answer
I fixed the problem by defining my own wrapper something like
function y = mywrapper(f, x)
%MYWRAPPER nargin(#(x)mywrapper(f, x)) is 1 as it should be
y = f(x);
end
I realised that nargin(#(x)#obj.foo), also does what I wanted
I'm working on a command line application for ultrasound simulation in MATLAB. Nearly every object in our code is a subclass of handle (to pass as references). The problem I'm having is that all the methods inherited from the handle class shows up under the "Methods" section in MATLAB (see example below).
What I want is to hide the inherited methods from the handle class so that only the function the user is allowed to use is shown under "Methods". This way it doesn't look so messy for the user if he/she wants to know which methods to use.
Example Test class:
classdef Test < handle
methods
function myFunction(obj)
end
end
end
In the command line:
T = Test()
T =
Test handle with no properties.
Methods, Events, Superclasses
After clicking on "Methods":
Methods for class Test:
Test delete findobj ge isvalid lt ne
addlistener eq findprop gt le myFunction notify
What I want:
Methods for class Test:
Test myFunction
Is this possible in MATLAB?
If you overload all of the subclass methods in a hidden methods block I think it will do exactly what you're looking for.
I'm not sure which versions of Matlab this works in, but it definitely works for me in R2012b.
The exception is isvalid as it is Sealed so you can't override it in a handle subclass.
classdef handle_light < handle
methods(Hidden)
function lh = addlistener(varargin)
lh = addlistener#handle(varargin{:});
end
function notify(varargin)
notify#handle(varargin{:});
end
function delete(varargin)
delete#handle(varargin{:});
end
function Hmatch = findobj(varargin)
Hmatch = findobj#handle(varargin{:});
end
function p = findprop(varargin)
p = findprop#handle(varargin{:});
end
function TF = eq(varargin)
TF = eq#handle(varargin{:});
end
function TF = ne(varargin)
TF = ne#handle(varargin{:});
end
function TF = lt(varargin)
TF = lt#handle(varargin{:});
end
function TF = le(varargin)
TF = le#handle(varargin{:});
end
function TF = gt(varargin)
TF = gt#handle(varargin{:});
end
function TF = ge(varargin)
TF = ge#handle(varargin{:});
end
function TF = isvalid(varargin)
TF = isvalid#handle(varargin{:});
end
end
end
If you save the above class to handle_light.m and then type methods handle_light in the command window you will get the following result:
Methods for class handle_light:
handle_light isvalid
The Test class then becomes:
classdef Test < handle_light
methods
function myFunction(obj)
end
end
end
Doing it in this way means that you don't need to put the overloads in the Test class which keeps things neater.
There is a solution here, including sample code.
In short, what you need to do is to overload Matlab's built-in function methods, so that when it is called on your class, it removes the methods of handle from the output. Make sure it works on everything else, though so that you don't mess up your user's other code. If you don't use the #foldername variant to store your class, you could put it into a private directory, for example.
Not a full solution, but if you do methods(T, '-full'), then it at least tells you which methods are inherited from handle, so you know what to ignore.
Just get the functions from the inherited class and cancel them out with the ones from the main class using setdiff.
mH = methods('handle');
m = methods('MyClass');
m = setdiff(m,mH);
I am trying to implement save/load functions in a MATLAB (R2009a) UI. My object implements a layout function that generates a user interface for the object. I am trying to implement the callbacks for the save/load buttons. The save button works and save the object out to a MAT file which can be loaded later.
My problem is implementing the callback for the load button. I cannot seem to get the load to load the data from the MAT file and update the properties of the new object. Any suggestions on where I am going wrong along with suggestions on how I might proceed is greatly appreciated.
The important code is my class definition file of course my actual object implements many more properties and methods but here is a skeleton of what I have
classdef myObj<handle
properties
image % property holds a matlab image matrix
objCount % number of objects in image
end
properties(Transient=true)
parent
children
end
methods
function myObj
% empty constructor
end
function load_object(self)
% ask user for file
[fileName, pathToFile]=uigetfile('*.mat','Select .mat file');
tmp = load(fullfile(pathToFile,fileName);
if isfield(tmp,'obj')
self = tmp.obj;
end
end
LayoutFcn(self) % UI layout function
end
end
The UI layout is defined in a seperate file LayoutFcn.m which basically looks like
function LayoutFcn(self)
% create figure window and add various UI elements
...
% create load button
self.children(end+1) = uipushtool('Parent',hToolbar, ... % set parent to current toolbar
'CData',iconRead('open-document.png'), ... % read icon image from file
'Tag','uiLoad', ...
'ClickedCallback',#(hObj,event)loadingMyObject(self,hObj,event));
% create save button
self.children(end+1) = uipushtool('Parent',hToolbar, ... % set parent to current toolbar
'CData',iconRead('save-document.png'), ... % read icon image from file
'Tag','uiSave', ...
'ClickedCallback',#(hObj,event)savingMyObject(self,hObj,event));
...
end
function loadingMyObject(self,hObj,event)
self.load_object; % call load_object method defined above in class definition
end
function savingMyObject(self,hObj,event)
[fileName,pathName]=uiputfile('.mat','Save object to MAT file');
obj = self;
save(fullfile(pahtName,fileName),'obj')
end
Note: I am using MATLAB R2009a.
The code doesn't throw any errors. The way I wrote the code the parent object (represented by self) does not get updated after the call to LOAD in the method load_object. SO, this has the desired effect:
>> var = myObj;
>> var.load_object;
However, if I use the loadingMyObject callback defined in LayoutFcn.m in this fashion
>> var = myObjl
>> var.LayoutFcn
-> click Load button to call _loadingMyObject_
doesn't affect var properties. That is var will still have its default property values after clicking the Load button.
Changing the load methods to use set as suggested by gnovice throws the following error
??? Error using ==> set
Conversion to double from FujiCalibration is not possible.
even though I have set/get methods for each property; as in
method set.image(self,II)
% ... some data validation code ...
self.image = II
end
Using a loop to set each field as suggested by Mr Fooz is not really an option as my full class has public constant that throw an error when they are set.
I am looking for a solution that would avoid me having to hand code setting each field individually. Although at this point it seems like the only possibility.
I believe Mr Fooz is right. The self variable passed to load_object is an object of type "myObj", but the line:
self = tmp.obj;
is simply overwriting the self variable with the structure stored in tmp.obj. Doing:
self.image = tmp.obj.image;
should instead invoke a set operator for the image property of object self. In the MATLAB documentation there is a sample class definition with a method called "set.OfficeNumber" that illustrates this.
In addition, the following line in your function savingMyObject may be unnecessary:
obj = self;
I think it might make most sense (and make the code a little clearer) if you used the name "obj" in place of the word "self" within your class code (as the documentation tends to do). "self" doesn't appear to be any kind of special keyword in MATLAB (like it may be in other languages). It's just another variable as far as I can tell. =)
EDIT #1:
If the prospect of having to set each property individually in your load_object method doesn't sound like fun, one way around it is if you have a SET method for your object that is designed like the SET method for handle graphics. That SET command can accept a structure input where each field name is a property name and each field value is the new value for that property. Then you would have one call like:
set(self,tmp.obj);
Quite a bit shorter, especially if you have lots of properties to set. Of course, you'd then have to write the new SET method for your object, but the shortened syntax may be worth the extra work if it comes in handy elsewhere too. =)
EDIT #2:
You may be able to use the loop Mr Fooz suggested in conjunction with a try/catch block:
fn = fieldnames(tmp.obj);
for i = 1:numel(fn),
try
self.(fn{i}) = tmp.obj.(fn{i});
catch
% Throw a warning here, or potentially just do nothing.
end
end
Don't assign values to self. All that does is replace the binding to the self variable in the scope of the method call. It does not call a magical copy constructor to replace the object reference in the caller. Instead, copy the fields into self. Try something like:
if isfield(tmp,'obj')
self.image = tmp.obj.image;
self.objCount = tmp.obj.objCount;
end
Combining Mr Fooz's and gnovice's suggestions, I added a SET function with the following definition
function set(self,varargin)
if isa(varargin{1},'FujiCalibration')
tmp = varargin{1};
fns = fieldnames(self);
for i = 1:length(fns)
if strcmpi(fns{i}(1:2),'p_')
self.(fns{i}) = tmp.(fns{i});
end
end
self.calibImage = tmp.calibImage;
else
proplist=fields(self);
for n=1:2:length(varargin)
tmp = proplist(strcmpi(proplist,varargin{n}));
value = varargin{n+1};
switch length(tmp)
case 0
msg = char(strcat('There is no ''', varargin{n}, '''property'));
error('FujiCalibration:setPropertyChk',msg)
case 1
tmp = char(tmp);
self.(tmp) = value;
end
end
end
end
I then modified the load_object method as suggested by gnovice by changing
self = tmp.obj
to
set(self,tmp.obj).
I need to make sure that properties with values I want to persist are prefixed with 'p_'.
Thanks to gnovice and Mr Fooz for their answers.