Subclassing Matlab built-in types w/ properties: concise basic operations and flexible superclass
    6 visualizzazioni (ultimi 30 giorni)
  
       Mostra commenti meno recenti
    
Hello all, 
I recently realized that there is considerable inherent power in subclassing Matlab primitives like double or char (edit, char is sealed and cannot be sub-classed). There is a good series of articles here.
Now, I want to create a numeric class that functions just like double, single, int16, etc generally, but with its own custom properties and methods. Let's use the following example
classdef temperature < double
    properties
        units = 'K';
    end
    methods
        function obj = temperature(data,unit)
            if nargin == 0
                data = 0;
                unit = 'K';
            elseif nargin == 1
                unit = 'K';
            end
            obj = obj@double(data);
            obj.units = unit;
        end
        function sref = subsref(obj,s)
            switch s(1).type
                case '.'
                    switch s(1).subs
                        case 'units'
                            sref = obj.units;
                        case 'Data'
                            d = double(obj);
                            if length(s)<2
                                sref = d;
                            elseif length(s)>1 && strcmp(s(2).type,'()')
                                sref = subsref(d,s(2:end));
                            end
                        otherwise
                            error('Not a supported indexing expression')
                    end
                case '()'
                    d = double(obj);
                    newd = subsref(d,s(1:end));
                    sref = temperature(newd,obj.units);
                case '{}'
                    error('Not a supported indexing expression')
            end
        end
        function obj = subsasgn(obj,s,b)
            switch s(1).type
                case '.'
                    switch s(1).subs
                        case 'units'
                            obj.units = b;
                        case 'Data'
                            if length(s)<2
                                obj = temperature(b,obj.units);
                            elseif length(s)>1 && strcmp(s(2).type,'()')
                                d = double(obj);
                                newd = subsasgn(d,s(2:end),b);
                                obj = temperature(newd,obj.units);
                            end
                        otherwise
                            error('Not a supported indexing expression')
                    end
                case '()'
                    d = double(obj);
                    newd = subsasgn(d,s(1),b);
                    obj = temperature(newd,obj.units);
                case '{}'
                    error('Not a supported indexing expression')
            end
        end
        function obj = minus(obj,B)
           a = double(obj);
           b = double(B); 
           newd = a - b;
           obj = temperature(newd,obj.units); 
        end
        function obj = rdivide(obj,B)
            a = double(obj);
            b = double(B);
            newd = a./b;
            obj = temperature(newd,obj.units);
        end
        function obj = times(obj,B)
            a = double(obj);
            b = double(B);
            newd = a.*b;
            obj = temperature(newd,obj.units);
        end
         function obj = mtimes(obj,B)
            a = double(obj);
            b = double(B);
            newd = a*b;
            obj = temperature(newd,obj.units);
         end
          function obj = mrdivide(obj,B)
            a = double(obj);
            b = double(B);
            newd = a/b;
            obj = temperature(newd,obj.units);
        end
        function obj = plus(obj,B)
           a = double(obj);
           b = double(B); 
           newd = a + b;
           obj = temperature(newd,obj.units); 
        end
        function obj = farenheit(obj)
           switch obj.units
               case 'K'
                   obj = obj*9/5 - 459.67;
                   obj.units = 'F';
           end
        end
         function obj = kelvin(obj)
           switch obj.units
               case 'F'
                   obj = (obj + 459.67)*5/9;
                   obj.units = 'K';
           end
        end
    end
end
Here, I have set up a class that has an associated 'units' to describe its value (one can imagine additional attached metadata). I have set up the required methods for data access and assignment (subsasgn and subsref) a series of basic math operations (mdivide,plus,times,etc.) that allow me to return an object of the temperature class if I do, for example: 
T = temperature(70+rand(10,1),'F');
T2 = T + 5; 
This generally works fairly well, but I have two major questions: 
- Is there a way to 'generify' the operation that are methods of the superclass, double? This would be for the basic operations plus, minus, etc. which all follow the same basic form: convert the object to a double, do the operation on the double data, then convert back to the temperature class. It seems like unnecessary code to have to reimplement all of the methods of double (see methods(double.empty) for the whole list) in this manner. Is there a way to simplify this? Nominally something like:
function obj = genop(obj,optype,B,varargin)
    if ismethod(double.empty,optype)
       a = double(obj);
       b = double(B); 
       d = feval(@(optype),a,b),varargin{:})
       obj = temperature(d,obj.units)
    end
end
    where I can still use e.g. obj2 = obj + 5 and have it return the expected values as a temperature. 
- Is there a way to 'generify' the superclass. Nominally so that I can store the temperature as a double,single, gpuArray,int32, etc. without having to create independent versions of the subclass for each superclass (e.g classdef temperatureS < single, and replacing all of the double commands above by single). This also seems like redundant code, and a recipe for errors as one would need to make sure any changes were replicated across all versions. Would it be better not to subclass double at all, and instead use a data holder property obj.Data and just use cast? e.g.
classdef temperature
    properties
        data
        units
    end
    % Make subsasgn and subsref so it mimics a numeric array
    methods
        function obj = plus(obj,B)
            c = class(obj.data);
            b = cast(B,c);
            d = obj.data +  b;
            obj = temperature(d,obj.units);
        end
    end
end
but this seems to remove any of the advantages of subclassing a built-in primitive type. 
Are there any other obvious tricks/pitfalls to subclassing Matlab built-in classes?
Cheers, 
DP
0 Commenti
Risposte (0)
Vedere anche
Categorie
				Scopri di più su Assembly in Help Center e File Exchange
			
	Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!
