Within a subclass constructor, what is the difference between calling obj#SuperClass(a,b); and obj = obj#SuperClass(a,b);
Both are found in doc, for ex. here
The canonical syntax for calling a superclass constructor is
obj = obj#SuperClass(args)
(see the documentation).
This is comparable to calling any constructor, where the output of the function call is assigned to a variable:
obj = SuperClass(args)
However, because the superclass constructor must initialize fields inside a (larger) derived object, the obj to be modified must be passed in some way to the function call, hence the (awkward) obj# syntax.
But because we pass the object to be initialized, which is modified, we don’t really need to capture that output any more. Hence the other form,
obj#SuperClass(args)
does exactly the same things in all situations I have encountered.
There is no difference that I can see. I would be surprised if the first syntax did any data copying whatsoever, that has most certainly been optimized out, just like obj = obj.method(args) doesn’t copy the object.
Related
I tried to change an attribute value of a class by invoking one of its member function:
p1 = tank();
p1.checkOri(p1);
And in the class definition, I have that static method:
classdef tank
properties
value
...
end
methods
...
methods (Static)
function obj = checkOri(obj)
if (CONDITION) %the thing I want it to do
obj.value = EXPRESSION;
...
Yet this checkOri method is not working. But if I write this method in the main file, or to say altering the value of p1-the instance of class tank-it works perfectly:
p1 = tank();
p1.checkOri(p1);
if (CONDITION) %the thing I want it to do
p1.value = EXPRESSION;
It works perfectly.
I wonder what caused this. From my experience with other programming languages, invoking method should have worked, is it because of some tricks with Matlab syntax or static method? How could I fix it so that this method would work?
So, as #Navan in the comment said, handle class could be a solution.
It appears Matlab has a similar parameter concept with Java and C++, arguments modified in a function/method only remains that modification inside the function/method.
For this class, I simply added < handle in the head of class definition and it worked:
classdef tank < handle
properties
...
But I am not sure if that is the only solution, there might be better ways to do this. So I'll leave that question open, you are more than welcomed to post your opinion:D
In MATLAB, the call
p1.checkOri();
is equivalent to
checkOri(p1);
In both cases, the class method checkOri is called for the class of object p1, passing p1 as first argument to the function by value.
Because p1 is passed by value, any changes made to it inside the function are not seen by the object in the calling workspace. Therefore, one typically does
p1 = checkOri(p1);
This way, the object that was passed by value and modified inside the function is passed back out and assigned to the variable that held the original object.
If the method is written as follows:
function obj = checkOri(obj)
%...
end
then MATLAB will optimize the above function call such that no copy of the object is actually made. Note that both in the function declaration and in the function call, the input and output variable is the same.
As already discovered by OP, the above does not hold for handle classes, classes that inherit from handle. These classes act as if they are always passed by reference, and any change made to them in any workspace will be reflected in all other copies in other workspaces.
Also assigning to a member variable does not follow the above, such that
p1.value = 0;
modifies object p1.
For more information on the difference between value classes and handle classes see this other question.
After evolving my project code for months, I've finally hit a need to define a new class. Having to romp through my previous class definitions as a refresher of the conventions, I noticed that all constructors and property setters all have an output argument, even though nothing is assigned to it, e.g.:
function o = myConstructor( arg1, arg2, ... )
function o = set.SomeProperty( o, arg1 )
I've been looking through the documentation for upward of an hour without finding the explanation for this. It doesn't look like it depends on whether a function is defined in the class definition file or in its own separate m-file.
Can anyone please explain?
The best place to start is the documentation "Comparison of Handle and Value Classes". From the very top:
A value class constructor returns an object that is associated with the variable to which it is assigned. If you reassign this variable, MATLAB® creates an independent copy of the original object. If you pass this variable to a function to modify it, the function must return the modified object as an output argument.
A handle class constructor returns a handle object that is a reference to the object created. 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. A function that modifies a handle object passed as an input argument does not need to return the object.
In other words, value classes need to return a modified object (which is a new object distinct from the original), while handle classes don't. The constructor of either class will always have to return an object, since it is actually constructing it.
Some good additional reading is "Which Kind of Class to Use", which links to a couple helpful examples of each type of class object. Looking at the DocPolynom value class example, you can see that property set methods have to return the modified object, while the dlnode handle class example only requires an output for its constructor. Note that you could still return an object from a handle class method (if desired), but it's not required.
In my example, I have a class representing a certain set of data. Some of the data's properties are written to the class' properties, while the class' methods mostly perform tasks like reading the raw data from spreadsheets and doing some pre-calculations.
I was wondering if the following is according to the "pure doctrine" of OOP, and if not, if and how it could be syntactically improved.
Here is a very simple (untested) implementation of such a class.
classdef dataObjectTest < handle
properties
filename char
pathFilename char
rawData double
end
methods
function obj = setPathnameFromFilename(obj, filename)
%setPathnameFromFilename Determine full path- & filename from single filename
% filename: Name of the file containing the raw data, e.g., 'Test.xls'
obj.filename = filename;
intermed = dir(obj.filename);
obj.pathFilename = fullfile(intermed.folder, obj.filename);
end
function obj = loadRawDataFromSpreadsheet(obj)
% loadRawDataFromSpreadsheet Convert the raw data stored in a spreadsheet into a Matlab
% array, using the full path- & filename determined by setPathnameFromFilename
% rawData: Array contating the raw data
obj.rawData = xlsread(obj.pathFilename);
end
end
end
And here is how one would call this class from another program/script:
test = dataObjectTest;
test.setPathnameFromFilename('Test.xls');
test.loadRawDataFromSpreadsheet;
I am especially concerned about the third line. Since both input and output arguments of the method loadRawDataFromSpreadsheet are properties of the class, it is unnecessary to explicitly define them in the function header. On the other hand, this implementation seems somehow awkward to me and not in "spirit" of OOP, which is a lot about clearly defined interfaces between the user and the class.
So although my code works, I'm still wondering if this is "the right way" to do it or if could be significantly improved.
UPDATE: Admittedly, the choice of my methods' names may have been misleading, but this was not the point of the question. So let me try to clarify.
The first method takes the user-given string filename and returns pathFilename. But since this is also a property of the class, it is not visible from the function signature, i.e., the function should look like:
function pathFilename = setPathnameFromFilename(obj, filename)
But this doesn't work in Matlab. (The varName = part corresponds to return varName in other languages.)
The second method returns the array rawData, and since the input argument pathFilenameis, again, a property of the class, neither are visible in the method's signature.
So my concern was about having methods which actually have in- and output arguments, but do not reveal them through their signature.
It's basically fine, but I'd implement it like this:
classdef dataObjectTest < handle
properties
filename char
pathname char
rawData array
end
methods
function loadRawDataFromSpreadsheet(obj, filename)
obj.filename = filename;
obj.pathname = dataObjectTest.extractPathName(filename
obj.rawData = xlsread(obj.pathname);
end
end
methods (Static, Access = private)
function pathname = extractPathName(filename)
intermed = dir(filename);
pathname = fullfile(intermed.folder, filename);
end
end
end
Notes:
Since it's a handle object, you don't need obj as an output argument of the main method.
I've moved the extraction of the path to a private static method, as it's really a utility function (you could instead implement as an actual subfunction rather than a method).
I've renamed the main method to start with load rather than get, to make sure it isn't mistaken for a property get method.
I wouldn't worry too much about the "spirit of OOP" - instead, just make sure your code works, is well-organised, is testable, and maintainable.
It is just fine according to the "doctrine" of pure OOP for a method to have no in or out parameters apart from the object reference.
However, what you are doing doesn't conform to normal practice for method naming. A method with a name starting with get is normally a "getter". The primary purpose of a "getter" is to return some component of the class. Generally speaking, a "getter" should not modify the target object.
But you have two get... methods that 1) modify the target object and 2) don't return anything.
In my opinion:
the first one should be named setPathnameFromFilename or maybe just setFilename.
the second one should be named loadRawDataFromSpreadsheet or something like that.
On the other hand, this implementation seems somehow awkward to me and not in "spirit" of OOP, which is a lot about clearly defined interfaces between the user and the class.
I actually don't see that at all. Sure, the interface is not clearly defined, but that is largely because you have not documented the methods and because you have chosen (IMO) misleading / non-informative class and method names.
(Disclaimer: I am a Java programmer. However, the basic principles of OOP are largely the same for all OO languages.)
For example:
function s = slexpdatasetSLAP()
s = s#slexpdataset('slapCC','SLAP dataset for collective classification'); %slexpdataset is a class defined in another .m file
s.discription ='CC';
end
As I know, # is used as creating a function handle in MATLAB, but obviously that interpretation is not suitable in this context. So what does that at # mean?
This is the syntax for calling the constructor of the super-class
In general, for calling a method of the superclass, you'd use the syntax
outputs = methodName#superclassname(obj, input, arguments)
However, calling the constructor is a little different since you use the variable name for your object's instance in place of methodName in the example above
obj = obj#superclassname(input, arguments)
In your case, rather than obj, you're using s as the variable to refer to the class instance (since you define that as the output from your constructor), so you're essentially calling the constructor of slexpdataset and passing it the list of arguments shown.
I just read that the init method can't be used as a value. Meaning:
var x = SomeClass.someClassFunction // ok
var y = SomeClass.init // error
Example found on Language reference
Why should it be like that? Is it a way to enforce language level that too dirty tricks come into place, because of some cohertion or maybe because it interferes with another feature?
Unlike Obj-C, where the init function can be called multiple times without problems, in Swift there actually is no method called init.
init is just a keyword meaning "the following is a constructor". The constructor is called always via MyClass() during the creation of a new instance. It's never called separately as a method myInstance.init(). You can't get a reference to the underlying function because it would be impossible to call it.
This is also connected with the fact that constructors cannot be inherited. Code
var y = SomeClass.init
would also break subtyping because the subtypes are not required to have the same initializers.
Why should it be like that?
init is a special member, not a regular method.
Beyond that, there's no reason that you'd ever need to store init in a variable. The only objects that could use that function in a valid way are instances of the class where that particular init is defined, and any such object will have already been initialized before you could possibly make the assignment.
Initializers don't have a return value. In order to assign it to something, it should be able to return something - and it doesn't.