Class Support for Array-Creation Functions - MATLAB & Simulink (original) (raw)

Extend Array-Creation Functions for Your Class

There are several MATLAB® functions that create arrays of a specific size and type, such asones and zeros. You can overload many of these functions to work specifically with your classes. That process is described in this topic. For options for creating object arrays without overloading existing functions, see Create and Initialize Object Arrays.

Note

createArray (since R2024a) supports array creation for many classes without the need for overloading. For more information, see createArray. For information about cases when overloadingcreateArray might be useful, see createArray Methods to Implement.

Class support for any of the array-creation functions enables you to develop code that you can share with built-in and user-defined data types. For example, the class of the variable x in the following code can be a built-in type during initial development, and then be replaced by a user-defined class that transparently overloads zeros:

cls = class(x); zArray = zeros(m,n,cls);

Array-creation functions create arrays of a specific type in two ways:

For example:

zArray = zeros(2,3,'uint8');

p = uint8([1 3 5; 2 4 6]); zArray = zeros(2,3,'like',p);

After adding support for these functions to a class namedMyClass, you can use a similar syntax with that class:

zArray = zeros(2,3,'MyClass');

Or pass an object of your class:

p = MyClass(...); zArray = zeros(size(p),'like',p);

MATLAB uses these arguments to dispatch to the appropriate method in your class.

Array-Creation Functions That Support Overloading

These functions support this kind of overloading:

Scalar Functions That Support Overloading

These functions also support similar overloading, with the exception that the output is always a scalar (or a 1-by-1 sparse matrix):

For these functions, you do not need to specify the size when creating scalars of a specific type. For example:

p = single([1 3 5; 2 4 6]); d = eps('like',p);

After adding support for these functions to a user-defined class, you can use similar syntax with that class as well.

Which Syntax to Use

Classes can support both the class name and the prototype object syntax. To create an array of default objects, use the class name syntax. To create an array of objects with the same type, complexity, and other properties as an existing object, use the prototype syntax.

Implement Support for Array-Creation Functions

Use two separate methods to support an array-creation function. One method implements the class name syntax and the other implements the prototype object syntax.

For example, to support the zeros function:

How MATLAB Interprets the Function Call

The special support for array-creation functions results from the interpretation of the syntax.

Class Name Method Called If Prototype Method Does Not Exist

If your class implements a class name syntax, but does not implement a prototype object syntax for a particular function, you can still call both syntaxes. For example, if you implement a static zeros method only, you can call:

zeros(...,'like',MyClass(...))

In the case in which you call the prototype object syntax, MATLAB first searches for a method named zerosLike. If MATLAB cannot find this method, it calls for the zeros static method.

This feature is useful if you only need the class name to create the array. You do not need to implement both methods to support the complete array-creation function syntax. When you implement only the class name syntax, a call to a prototype object syntax is the same as the call to the class name syntax.

Support All Function Inputs

The input arguments to an array-creation function can include the dimensions of the array the function returns and possibly other arguments. In general, there are three cases that your methods must support:

When the array-creation function calls your class method, it passes the input arguments, excluding the class name or the literal 'like' and the object variable to your method. You can implement your methods with these signatures:

Sample Class

The Color class represents a color in a specific color space, such as, RGB, HSV, and so on. The discussions in Class Name Method Implementations and Prototype Object Method Implementation use this class as a basis for the overloaded method implementations.

classdef Color properties ColorValues = [0,0,0] ColorSpace = 'RGB' end methods function obj = Color(cSpace,values) if nargin > 0 obj.ColorSpace = cSpace; obj.ColorValues = values; end end end end

Class Name Method Implementations

The zeros function strips the final_ClassName_ char vector and uses it to form the call to the static method in the Color class. The arguments passed to the static method are the array dimension arguments.

Here is an implementation of a zeros method for theColor class. This implementation:

classdef Color ... methods (Static) function z = zeros(varargin) if (nargin == 0) % For zeros('Color') z = Color; elseif any([varargin{:}] <= 0) % For zeros with any dimension <= 0
z = Color.empty(varargin{:}); else % For zeros(m,n,...,'Color') % Use property default values z = repmat(Color,varargin{:}); end end end end

The zeros method uses default values for theColorValues property because these values are appropriate for this application. An implementation of a ones method can set the ColorValues property to[1,1,1], for example.

Suppose that you want to overload the randi function to achieve the following objectives:

classdef Color ... methods (Static) function r = randi(varargin) if (nargin == 0) % For randi('ClassName') r = Color('RGB',randi(255,[1,3])); elseif any([varargin{2:end}] <= 0) % For randi with any dimension <= 0 r = Color.empty(varargin{2:end}); else % For randi(max,m,n,...,'ClassName') if numel([varargin{:}]) < 2 error('Not enough input arguments') end dims = [varargin{2:end}]; r = zeros(dims,'Color'); for k = 1:prod(dims) r(k) = Color('RGB',randi(varargin{1},[1,3])); end end end end end

Prototype Object Method Implementation

The objective of a method that returns an array of objects that are “like a prototype object” depends on the requirements of the class. For the Color class, the zerosLike method creates objects that have the ColorSpace property value of the prototype object, but the ColorValues are all zero.

Here is an implementation of a zerosLike method for theColor class. This implementation:

classdef Color ... methods (Hidden) function z = zerosLike(obj,varargin) if nargin == 1 % For zeros('like',obj) cSpace = obj.ColorSpace; z = Color; z.ColorSpace = cSpace; elseif any([varargin{:}] <= 0) % For zeros with any dimension <= 0 z = Color.empty(varargin{:}); else % For zeros(m,n,...,'like',obj) if ~isscalar(obj) error('Prototype object must be scalar') end obj = Color(obj.ColorSpace,zeros(1,3,'like',obj.ColorValues)); z = repmat(obj,varargin{:}); end end end end

Full Class Listing

Here is the Color class definition with the overloaded methods.

Note

In actual practice, the Color class requires error checking, color space conversions, and so on. This overly simplified version illustrates the implementation of the overloaded methods.

classdef Color properties ColorValues = [0,0,0] ColorSpace = 'RGB' end methods function obj = Color(cSpace,values) if nargin > 0 obj.ColorSpace = cSpace; obj.ColorValues = values; end end end methods (Static) function z = zeros(varargin) if (nargin == 0) % For zeros('ClassName') z = Color; elseif any([varargin{:}] <= 0) % For zeros with any dimension <= 0 z = Color.empty(varargin{:}); else % For zeros(m,n,...,'ClassName') % Use property default values z = repmat(Color,varargin{:}); end end function r = randi(varargin) if (nargin == 0) % For randi('ClassName') r = Color('RGB',randi(255,[1,3])); elseif any([varargin{2:end}] <= 0) % For randi with any dimension <= 0 r = Color.empty(varargin{2:end}); else % For randi(max,m,n,...,'ClassName') if numel([varargin{:}]) < 2 error('Not enough input arguments') end dims = [varargin{2:end}]; r = zeros(dims,'Color'); for k = 1:prod(dims) r(k) = Color('RGB',randi(varargin{1},[1,3])); end end end end methods (Hidden) function z = zerosLike(obj,varargin) if nargin == 1 % For zeros('like',obj) cSpace = obj.ColorSpace; z = Color; z.ColorSpace = cSpace; elseif any([varargin{:}] <= 0) % For zeros with any dimension <= 0 z = Color.empty(varargin{:}); else % For zeros(m,n,...,'like',obj) if ~isscalar(obj) error('Prototype object must be scalar') end obj = Color(obj.ColorSpace,zeros(1,3,'like',obj.ColorValues)); z = repmat(obj,varargin{:}); end end end end

Overloading createArray

createArray (since R2024a) supports most classes without the need for overloading. However, if your class meets one or more of these conditions, implement the static createArray method:

Implement the createArrayLike method if your class does not support creating an array from an existing object through indexed assignment. However, most classes do not need to overloadcreateArrayLike becausecreateArray usually supports the preservation of property values.

The process of overloading the createArray function is similar to zeros, but the syntaxes are slightly different because of the FillValue name-value arguments forcreateArray.

createArray Methods to Implement

Method Function Signature When the Method Is Called
static createArray function obj = createArray(dims,F), where dims is a row vector of two or more nonnegative integers, and F is theFillValue (optional) createArray(dims,"ClassName")createArray(dims,"ClassName", FillValue=F)
createArrayLike function obj = createArrayLike(L,dims,F), wheredims is a row vector of two or more nonnegative integers, L is the prototype and F is the FillValue (optional) createArrayLike(dims,Like=L)createArrayLike(dims,Like=L,FillValue=F)

See Also

Topics