Main Content

How to Define Handle-Compatible Classes

What Is Handle Compatibility?

A class is handle compatible if:

  • It is a handle class

  • Its HandleCompatible attribute is set to true

The HandleCompatible class attribute identifies classes that you can combine with handle classes when specifying a set of superclasses.

Handle compatibility provides greater flexibility when defining abstract superclasses. For example, when using superclasses that support both handle and value subclasses, handle compatibility removes the need to define both a handle version and a nonhandle version of a class.

A Handle Compatible Class

The Utility class is useful to both handle and value subclasses. In this example, the Utility class defines a method to reset property values to the default values defined in the respective class definition:

classdef (HandleCompatible) Utility
   methods
      function obj = resetDefaults(obj)
         mc = metaclass(obj);
         mp = mc.PropertyList;
         for k=1:length(mp)
            if mp(k).HasDefault && ~strcmp(mp(k).SetAccess,'private')
               obj.(mp(k).Name) = mp(k).DefaultValue;
            end
         end
      end
   end
end

The Utility class is handle compatible. Therefore, you can use it in the derivation of classes that are either handle classes or value classes. See Class Introspection and Metadata for information on using meta-data classes.

Return Modified Objects

The resetDefaults method defined by the Utility class returns the object it modifies. When you call resetDefaults with a value object, the method must return the modified object. It is important to implement methods that work with both handle and value objects in a handle compatible superclass. See Object Modification for more information on modifying handle and value objects.

Consider the behavior of a value class that subclasses the Utility class. The PropertyDefaults class defines three properties, all of which have default values:

classdef PropertyDefaults < Utility
   properties
      p1 = datestr(rem(now,1)) % Current time
      p2 = 'red'               % Character vector
      p3 = pi/2                % Result of division operation
   end
end

Create a PropertyDefaults object. MATLAB® evaluates the expressions assigned as default property values when the class is first loaded. MATLAB uses these same default values whenever you create an instance of this class in the current MATLAB session.

pd = PropertyDefaults
pd = 

  PropertyDefaults with properties:

    p1: ' 4:42 PM'
    p2: 'red'
    p3: 1.5708

Assign new values that are different from the default values:

pd.p1 = datestr(rem(now,1));
pd.p2 = 'green';
pd.p3 = pi/4;

All pd object property values now contain values that are different from the default values originally defined by the class:

pd
pd = 

  PropertyDefaults with properties:
:
    p1: ' 4:45 PM'
    p2: 'green'
    p3: 0.7854

Call the resetDefaults method, which is inherited from the Utility class. Because the PropertyDefaults class is not a handle class, return the modified object.

pd = pd.resetDefaults
pd = 

  PropertyDefaults with properties:

    p1: ' 4:54 PM'
    p2: 'red'
    p3: 1.5708

If the PropertyDefaults class was a handle class, then you would not need to save the object returned by the resetDefaults method. To design a handle compatible class like Utility, ensure that all methods work with both kinds of classes.

Subclassing Handle-Compatible Classes

According to the rules described in Handle Compatibility Rules, when you combine a handle superclass with a handle-compatible superclass, the result is a handle subclass, which is handle compatible.

However, subclassing a handle-compatible class does not necessarily result in the subclass being handle compatible. Consider the following two cases, which demonstrate two possible results.

Combine Nonhandle Utility Class with Handle Classes

Suppose that you define a class that subclasses a handle class, and the handle compatible Utility class discussed in A Handle Compatible Class. The HPropertyDefaults class has these characteristics:

  • It is a handle class (it derives from handle).

  • All its superclasses are handle compatible (handle classes are handle compatible by definition).

classdef HPropertyDefaults < handle & Utility
   properties
      GraphPrim = line
      Width = 1.5
      Color = 'black'
   end
end

The HPropertyDefaults class is handle compatible:

hpd = HPropertyDefaults;
mc = metaclass(hpd);
mc.HandleCompatible
ans =

     1

Nonhandle Subclasses of a Handle-Compatible Class

If you subclass both a value class that is not handle compatible and a handle compatible class, the subclass is a nonhandle compatible value class. The ValueSub class:

  • Is a value class (it does not derive from handle.)

  • One of its superclasses is handle compatible (the Utility class).

classdef ValueSub < MException & Utility
   methods
      function obj = ValueSub(str1,str2)
         obj = obj@MException(str1,str2);
      end
   end
end

The ValueSub class is a nonhandle-compatible value class because the MException class does not define the HandleCompatible attribute as true:

hv = ValueSub('MATLAB:narginchk:notEnoughInputs',...
      'Not enough input arguments.');
mc = metaclass(hv);
mc.HandleCompatible
ans =

     0

Related Topics