After asking my previous question I have come to a situation where I use a couple of object classes stored in each other's properties to retain access to several fields and methods. For example
classdef Class1
properties
Class1Prop % A property accessible from Class1
Class2 % A cell array of class 2 objects
end
methods
% Construct the class with all of its properties
function self = Class1()
end
function Class1Method
self.Class1Prop = ...
end
end
end
I populate an object of Class1 that contains a cell array of Class2. Now I would like to have methods change the values of properties inside of this object. i.e.
Class1{index}.Class2{index}.Class2Method
Will perform some computation and now have that value stored somewhere in that instance of the class.
As stated in the matlab documentation:
"If a function modifies a handle object passed as an input argument,
the modification affects the object referenced by both the original
and copied handles."
To gain the functionality I want, I have to use value classes (with methods that return the class object) so that the value returned by the method call is changed. The value returned can be assigned as well:
Class1{index}.Class2{index} = Class1{index}.Class2{index}.Class2Method
However, ideally
Class1{index}.Class2{index}.Class2Method
would update the Class2 properties. And that is the functionality I want. Is this possible?
Class1{index}.Class2{index} = Class1{index}.Class2{index}.Class2Method
Is the ideal way to address the stated need. It is made possible by using value classes populated by a handle class.
Related
Is there any way to get the value of an objects' private attribute without a getter. Modifying the class is not permitted in any shape or form.
Please find below an example class with a private attribute.
CLASS counter DEFINITION.
PUBLIC SECTION.
METHODS: set IMPORTING value(set_value) TYPE i.
PRIVATE SECTION.
DATA count TYPE i.
ENDCLASS. "counter DEFINITION
CLASS counter IMPLEMENTATION.
METHOD set.
count = set_value.
ENDMETHOD. "set
ENDCLASS. "counter IMPLEMENTATION
How can I get the value of count? Inheriting from counter will not work because count is private, not protected.
Unfortunately not, I have tried this myself in many different ways none of which work:
Having a standard super class - the super class cannot access the
private attributes of subclasses dynamically
Making a subclass will never work since it can only access protected
Attempting to use the unit test framework doesn't work. I tried to
call the kernel modules that allow access to private data but to no
avail.
You are basically flat out of luck. There is one obscure option though depending on the class you are trying to access. Some classes have interfaces specified as friends and if you implement that interface you can access their private data (the ALV on 7.20 is like this) but unfortunately this will only work in a few limited cases.
Runtime type services are the abap's equivalent of reflection.
They allow You nearly to scan every object, and mostly even modify it at runtime. As far as i know, the visibility of attributes does not matter. But be careful.
And read about the various classes, because there are many, each specified to work on a special type of dataopbject ( structs, objects, etc)
http://wiki.scn.sap.com/wiki/pages/viewpage.action?pageId=42965
You could make a sub class, re-implement the setter and set a second variable, then call the parent method. Be aware of the ramifications of having two variables holding the same stuff... Please see vwegert's comments and see if you really want to because it's generally not a great idea and it breaks the rules of OO.
CLASS counter_sub DEFINITION INHERITING FROM counter.
PUBLIC SECTION.
data count2 type i read-only.
METHODS: set REDEFINITION.
ENDCLASS. "counter_sub DEFINITION
CLASS counter_sub IMPLEMENTATION.
METHOD set.
count2 = set_value.
super->set( set_value ).
ENDMETHOD. "set
ENDCLASS. "counter_sub IMPLEMENTATION
In Matlab I have a class
classdef myClass
properties
% some properties here...
end
methods ( Access = 'public' )
function obj = myClass()
% constructor...
end
function obj = delete( obj )
% suppose to be destructor...
fprintf(1, 'delete\n');
end
end % public methods
end
What is the default behavior of Matlab when I clear a variable of type myClass?
For example:
>> m = myClass();
>> clear m
I would expect Matlab to call the destructor of m at this stage, but it seems like it doesn't!!
My questions:
How can I force a call to the destructor when clearing a variable?
Is this default behavior of Matlab's makes any sense? Isn't it more logical to call the destructor when clearing a variable?
Is it possible that Matlab's classes do not have a detructor method (that is, there is no default method to be called when the class is destroyed)? Or am I missing something?
Is it possible that only classes derived from handle have a destructor (the delete method)?
Thanks!
EDIT : following Jonas' answer, a brief summary:
Matlab has two types of classes: value classes (the default) and handle classes (derived from handle super class). Value classes tends to provide better performance, however, they do not have a destructor functionality.
handle classes do have a destructor function: delete that is called when the class is destroyed. See this question from more details on handle class destructors.
If one wishes to have a destructor-like functionality for value classes, Jona's answer proposes a method utilizing onCleanup functionality.
Thanks for the good answer and the insightful comments!
Delete is only defined as class destructor for handle classes, not value classes (so the answer to Q4 is "yes", see the previous link to the documentation). Value classes work very much like standard Matlab arrays, in that they're passed by value rather than by reference, and in that many of the internals, such as destructors, are hidden from the user. In exchange, they're usually faster (see for example this SO question).
Consequently, I suggest to use the onCleanup functionality if you want to have a delete method being called (note that delete(m) will not actually delete anything, so you may want to make that a private method).
classdef myTestClass
properties
% some properties here...
end
properties (Hidden)
cleanup
end
methods ( Access = 'public' )
function obj = myTestClass()
% constructor...
obj.cleanup = onCleanup(#()delete(obj));
end
end
methods ( Access = 'private' )
%# I suggest hiding the delete method, since it does not
%# actually delete anything
function obj = delete( obj )
fprintf(1, 'delete\n');
end
end % public methods
end
RealBasic's Introspection is kinda of different than what I expected.
My intention is:
Create a MainObject from which other objects will inherit two, three methods, to simplify.
Method 1-> Returns to the child class itself all of its properties, types and values.
Method 2-> Would call Method1 and with the information, save the child Object.
So, for method 1 I thought about writing a generalised introspection which for each child class would easily return what I need for Method 2 to do its work.
Why do I want this? So I can have tens of objects knowing how to save, draw themselves without worrying too much about a modification here or there on the properties etc...
But using what RealBasic tutorials and reference offers doesn't work, since it requires me to have it happening outside the object etc... i.e.: I can easily, inside ObjectA, get ObjectB's properties, methods etc, but I want to get inside ObjectA, A's properties, not B's
Thanks in advance...
I've found out how... Very simple, create the MainClass and inside of it a simple method WhoAmI which could return an array, dictionary etc...
Dim thisClassTypeInfo As Introspection.TypeInfo = Introspection.GetType(Self)
Dim thisClassProperties() As Introspection.PropertyInfo = thisClassTypeInfo.GetProperties
Dim thisClassMethods() As Introspection.MethodInfo = thisClassTypeInfo.GetMethods
For Each myProperty As Introspection.PropertyInfo In thisClassProperties
// Then here use myProperty.Name, myProperty.Value(Self).StringValue
// or myProperty.Value(Self).anyotheroption and create a dictionary
// or array with the results and return it.
Next
I'm trying to use single inheritance in Matlab, and to write a base class constructor that allows the creation of arrays of objects, including empty arrays, and which is inherited by subclasses. I can't work out how to do it without using some incredibly clunky code. There must be a better way.
In this toy example, my base class is called MyBaseClass, and my subclass is called MySubClass. Each can be constructed with a single numeric argument, or no arguments (in which case NaN is assumed). In the toy example my SubClass is trivial and doesn't extend the behavior of MyBaseClass in any way, but obviously in practice it would do more stuff.
I want to be able to call the constructor of each as follows:
obj = MyBaseClass; % default constructor of 'NaN-like' object
obj = MyBaseClass([]); % create an empty 0x0 array of type MyBaseClass
obj = MyBaseClass(1); % create a 1x1 array of MyBaseClass with value 1
obj = MyBaseClass([1 2; 3 4]) % create a 2x2 array of MyBaseClass with values 1, 2, 3, 4.
And the same four calls for MySubClass.
The solution I have found needs to call eval(class(obj)) in order to recover the subclass name and construct code in strings to call while in the base class constructor. This seems clunky and bad. (And it's somewhat surprising to me that it's possible, but it is.) I guess I could duplicate more logic between the MyBaseClass and MySubClass constructors, but that also seems clunky and bad, and misses the point of inheritance. Is there a better way?
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% MyBaseClass.m
classdef MyBaseClass
properties
data = NaN
end
methods
% constructor
function obj = MyBaseClass(varargin)
if nargin == 0
% Handle the no-argument case
return
end
arg = varargin{1};
% assume arg is a numeric array
if isempty(arg)
% Handle the case ClassName([])
% Can't write this, because of subclasses:
% obj = MyBaseClass.empty(size(arg));
obj = eval([class(obj) '.empty(size(arg))']);
return
end
% arg is an array
% Make obj an array of the correct size by allocating the nth
% element. Need to recurse for the no-argument case of the
% relevant class constructor, which might not be this one.
% Can't write this, because of subclasses
% obj(numel(arg)) = MyBaseClass;
obj(numel(arg)) = eval(class(obj));
% Rest of the constructor - obviously in this toy example,
% could be simplified.
wh = ~isnan(arg);
for i = find(wh(:))'
obj(i).data = arg(i);
end
% And reshape to the size of the original
obj = reshape(obj, size(arg));
end
end
end
% end of MyBaseClass.m
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% MySubClass.m
classdef MySubClass < MyBaseClass
methods
function obj = MySubClass(varargin)
obj = obj#MyBaseClass(varargin{:});
end
end
end
% end of MySubClass.m
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Your solution is functional and embraces some loose MATLAB typing to achieve what you want. However, getting clean and structured OOP is probably going to require losing some of the functionality you want. At the same time, the best option for avoiding code duplication is templated/generic container classes but these are not supported in MATLAB at this time.
Your code mirrors the MATLAB documentation on Building Arrays in the Constructor and relies on MATLAB being a loosely typed language that enabled you to convert an object into an array of objects without problem. Exploiting this powerful and flexible feature of MATLAB does introduce some organizational issues and may undermine your efforts at clean, object oriented code.
Problems begin because the MyBaseClass constructor is not a true constructor for MyBaseClass.
Wikipedia says:
"In object-oriented programming, a constructor (sometimes shortened to ctor) in a class is a special type of subroutine called at the creation of an object. It prepares the new object for use, often accepting parameters which the constructor uses to set any member variables required when the object is first created. It is called a constructor because it constructs the values of data members of the class."
Notice that the MyBaseClass constructor is not constructing values for the object members. Instead, it is a function that sets the object equal to an array of objects of type MyBaseClass and tries to set their data members to some value. You can see where the obj is destroyed at set to an array here:
obj(numel(arg)) = eval(class(obj));
This behavior is especially unhelpful when you derive MySubClass from MyBaseClass because MyBaseClass isn’t supposed to assign a new object to the variable obj----MySubClass has already created the new object in obj and is simply asking MyBaseClass to construct the portion of the existing object in obj that MyBaseClass knows the details for.
Some clarity might be gained by noting that when you enter the constructor for both MyBaseClass and MySubClass the variable obj is already populated with a perfectly good instance of the class. Good OOP practice would have you keep this original instance, use it in the base class constructor, and only act to populate its members in the constructor----not to overwrite the object entirely with something new.
My conclusion would be to not assign obj to be an array inside of MyBaseClass. Instead, I would recommend creating a class MyBaseClassArray that creates an array of MyBaseClass objects.
Unfortunately, you would also need to create a duplicate class MySubClassArray that creates an array of MySubClass objects. Languages like C++ and Java get around this code duplication issue with templates and generics, respectively but MATLAB does not currently support any form of templates (http://www.mathworks.com/help/techdoc/matlab_oop/brqzfut-1.html). Without templates there is no good way to avoid code duplication.
You could try and avoid some duplication by creating a generic CreateClassArray function that takes the string name of a class to create and the constructor arguments to use for each object---but now we are coming back to code that looks like your original. The only difference is now we have a clear division between the array class and the individual objects. The truth is that although MATLAB does not support templates, its flexible classes and typing system allow you use eval() like you have to change code and overwrite obj at will and create code that acts generically across classes. The cost? Readability, speed, and the uncomfortable feeling you got when you saw your base class constructing the subclass.
In short, you used MATLAB’s flexibility to overwrite the obj in the constructor with an array to avoid creating a separate container class for MyBaseClass. You then used eval to make up for not having a template feature in MATLAB that would allow you to reuse your array creation code all types. In the end, your solution is functional, reduces code duplication, but does require some unnatural behavior from your classes. It’s just a trade you have to make.
I'm working with vb.net, wcf, wpf and I'm refactoring working code with the hope of being able to reduce some amount of redundancy. I have a bunch of methods that get called in several places throughout the code that only have a slight variation from each other and I would like to replace them with a single method instead.
Specifically, each of the redundant methods process an 1-d array that contain different objects I have created. There are several of these different object types each with different signatures but they have all have a "name" and "Id" property. (Also these objects don't have a shared base class but I could add that if needed.) Each of the redundant methods deal with a different one of the object types.
To refactor the code I would like to pass any of the different object arrays to a single new method that could access the "name" and "id" properties. I'm trying to write this new method in a fashion that wouldn't require me to update it if I created more objects down the road.
I've done some reading on Delegates and Generic Classes but I can't really figure out how this fits in. It would almost be as if I wanted to create a generic class that could handle each of my object types but then somehow also access the "name" and "id" propeties of the different object types.
Any help you can provide would be appretiated. Also, please keep in mind this project is written in VB.net.
Thanks
Mike
It sounds like having your object implement a common interface or have a shared base class would be best. Interfaces give you the most flexibility down the road if you ever need to pass a class to this method that must derive from some other class that does not implement the interface. However, a base class that implements the interface may also be useful just to reduce the duplicate declarations of these properties.
Public Interface IThingThatHasNameAndId 'good name not included
ReadOnly Property Name As String
ReadOnly Property Id As Integer
End Interface
Once you have the interface, you can then pass arrays of types implementing the interface as IEnumerable(Of IThingThatHasNameAndId) or make a generic method taking T() and constrain T to the interface.
Make a base class with the Name and ID properties, then you can make a method that takes in any class that derrives from that class.
Public Function TestFunction(Of t As YourBaseClass)(Byval obj As t) As Boolean
If obj.Name = "Some Name" AndAlso obj.ID = 1 Then
Return True
Else
Return False
End If
End Function