Setting class property types

When I wrote about the undocumented aspects of classdef properties half a year ago, I did not expect to learn of another major undocumented aspect in Matlab’s class-object system. last month I discovered the additional undocumented classdef Description and DetailedDescription attributes, and updated that article accordingly. But a few days ago I was pleasantly surprised to read Amro’s comment about an entirely new and undocumented aspect of Matlab MCOS classes.

Amro is a top contributor on StackOverflow, where he frequently answers questions before I even get any subscription notification about them… His answers are generally characterized by a deep technical understanding of Matlab, and I’ve learned quite a lot from him in the past few years. This time was no different.

In a nutshell, Amro found an undocumented way to specify a class object property’s type, in such a way that would prevent accidental setting to an incompatible value. For example, if we have a class with properties Width and Height, we probably want to restrict their possible values to numbers, to prevent setting a string or struct value.

In UDD classes, we can do this easily by setting the property’s DataType meta-property. An easy way to do this is by setting the second argument of the schema.prop function. A detailed explanation was provided here.

We can still do this today, since UDD classes are still supported, side-by-side with the newer MCOS classes. Unfortunately, MCOS does not provide a documented way of specifying the property type as in UDD.

One simple way to prevent unintentional MCOS property updates is to override the property’s set method. In fact, this was the solution of Jonas, another StackOverflow heavyweight:

classdef myClass
   properties
      myProperty = uint16(23); %# specify default value using correct type
   end
   methods
      function obj = set.myProperty(obj,val)
         if ~isa(val,'uint16')
            error('only uint16 values allowed')
         end
         %# assign the value
         obj.myProperty = val;
      end
   end
end

But it turns out that there’s a much cleaner and simpler solution, provided by Amro:

classdef Packet
    properties
        HeaderLength@uint16
        PayloadLength@uint16 = uint16(0);
        PacketType@char
    end
end

As Amro notes, if you try to set a property with the wrong type, you get an error:

>> p = Packet;
>> p.PacketType = 'tcp';  % ok
>> p.HeaderLength = 100;  % not ok - should be a uint16
While setting the 'HeaderLength' property of Packet:
Value must be 'uint16'.

This syntax apparently supports all primitive types (char, int32, double, struct, cell etc.), in addition to any user-defined ones (just use any class name).

Note that setting the type as above seems to override any set method that may have been specified for the property.

Amro came across this syntax in an internal class in R2013a (toolboxdir(‘matlab’)/graphics/+graphics/+internal/+figfile/@FigFile/FigFile.m), but it also worked in R2012a, and probably older versions as well…

I admit there’s not much original work here by me – it’s basically all by Amro (and Donn Shull for the UDD part). But I thought it’s important enough to bring to the attention of the community.

I love to discover such undocumented treasures by digging in Matlab’s function. If you ever discover other such buried treasures, please do let me know by email or a comment.


Addendum June 21, 2013: As Sebastian Hölz mentioned in his comment below, the general syntax appears to be:

properties
   propName@className dimensionType = initialValue
end

where className, dimensionType and initialValue are optional elements:

  • className can be any Matlab class/type, such as double, single, or UserClass
  • dimensionType can be one of the following terms: scalar, vector, or matrix
  • the property may also be initiated with an initialValue (otherwise it receives a default value, depending on the property class)

Addendum August 12, 2014: In a related matter, we can limit the values that a property can accept using the matlab.system.StringSet class of the matlab.System package, as recently discovered by Oleg Komarov (additional details; additional aspects of class property tab-completion):

classdef foo < matlab.System
    properties
        Coordinates
    end
    properties(Hidden,Transient)
        CoordinatesSet = matlab.system.StringSet({'north','south','east','west'});
    end
end

restricting Matlab property values


Addendum April 8, 2015: As reported by Martin A. here and also below, R2015a has apparently added the new (and hidden) Type property to the meta.property class and the InputTypes and OutputTypes properties to the the meta.method class. This enables specifying and querying the types of properties as well as method inputs/outputs. For example:

mc = ?matlab.graphics.axis.Axes;
mc.PropertyList(1).Name % Camera
mc.PropertyList(1).Type % matlab.graphics.axis.camera.Camera
mc.MethodList(49).Name % addlistener
mc.MethodList(49).InputNames % [sources, propertyname, eventname, callback]
mc.MethodList(49).InputTypes % [handle, asciiString, char vector, function_handle scalar]

Addendum November 11, 2015: Apparently, when using the @double syntax, Matlab only allows the property to receive real values. In order to enable complex values, we can also add the undocumented “complex” attribute. Note that we have to enter the dimensionality (scalar/vector/matrix) first, since “complex” is not accepted as a valid dimensionality value. For example:

% This is ok:
classdef foo
    properties
        bar@double scalar complex = 1 + 2i    end
end
 
% This causes an error:
classdef foo
    properties
        bar@double complex = 1 + 2i    end
end

Addendum April 28, 2016: Matlab R2016a now has a similar documented functionality. However, I feel that there are important drawbacks to the new functionality compared to the one presented here. Read the full discussion about this.

The new (documented) syntax automatically type-casts the data to the specified data type, were possible, something that the undocumented (@) syntax presented above does not. In other words, the undocumented syntax is stricter and expects the data to be exactly the specified data type, without attempting any type-casting. As reported by Martin Afanasjew, we can add the property attribute to the data type to replicate the new syntax’s automatic type-casting:

classdef foo
    properties
        prop1@char = 'A'  % will only accept char inputs, not numeric values
        prop2@char property = 65  % will automatically type-cast: 65 will be converted to 'A'    end
end
Categories: Medium risk of breaking in future versions, Undocumented feature

Tags: , , , , ,

Bookmark and SharePrint Print

37 Responses to Setting class property types

  1. Donn Shull says:

    For users with Simulink there is a documented way for setting a few data types on properties using the PropertyType qualifier. Examples include

    properties(PropertyType = 'int32 scalar')

    and

    properties(PropertyType = 'char', AllowedValues ={'a', 'b', 'c'})

    When I discovered this I noticed that mlint flags this syntax as an error. I submitted a bug report to The MathWorks and have been informed that that this will be addressed in a future version of MATLAB. The MathWorks has updated the documentation to reflect this problem. To me this syntax seems slightly more readable than the form from this article (good catch finding this undocumented gem). It would be nice if The MathWorks extended this syntax to classdef in general and expanded the PropertyType specification to include all data types.

    • Jim Hokanson says:

      Interesting, however this seems like something that would be better to implement at the property level, and not for a set of properties. I am sure there was a decent amount of discussion at TMW about applying property attributes to a block or to each property. I sometimes find the block syntax to be highly disruptive to related properties that I would like to have grouped together, but that require different attributes. In this case it seems like allowed values and types would be better at the level of a property and not the block, although in the case of Simulink it seems like TMW felt otherwise.

    • Donn Shull says:

      With the R2012a release of MATLAB Simulink.Parameter and Simulink.Signal became MCOS objects. In previous releases they were UDD objects. The documented way to create subclasses of these classes before R2012a was to use a GUI known as the Simulink Data Class Designer. I suspect that the PropertyType qualifier was added to give some compatibility with the UDD version of these objects.

  2. Kristian Svartveit says:

    I have been using this from the first time I got a beta version of Matlab’s new OO classes. Never knew it wasn’t documented…

    K

    • Yair Altman says:

      @Kristian – interesting: Do you remember where you had first learned of this syntax?

  3. Jonas says:

    Thanks for the mention. I’m glad to have been able to contribute at least the “boring” example to your great blog :)

    • Yair Altman says:

      @Jonas – it’s a sad world that we live in, if the textbook solution is called “boring”…
      You, Amro and gnovice always seem to post detailed answers on SO so fast, before I even get a chance to see the questions. You don’t leave the little guys like me much of a chance to score rep points… :-)

  4. Amro says:

    @Donn Shull:
    matlab.System objects also have a similar documented qualifier, although less powerful. Only Logical and PositiveInteger are available: http://www.mathworks.com/help/comm/ref/matlab.systemclass.html

    For example:

    classdef Adder < matlab.System
        properties (PositiveInteger) % limit values to positive integers
            a = 1;
        end
        methods (Access=protected)
            function y = stepImpl(obj,x)
                y = x + obj.a;
            end
        end
    end

    with:

    h = Adder;
    h.a = -1;   % error
    h.a = 2;    % ok
    step(h,10)

    @Yair Altman:
    I did a search on my MATLAB installation, and I found only one other use of the prop@type syntax inside some file part of a Simulink toolbox: toolboxdir(‘sl3d’)/sl3d/+vr/@figure/figure.m (line 286).

    In fact my grep-fu skills uncovered a couple more undocumented OOP things! Many internal functions used by the Parallel Computing toolbox seem to be using custom property attributes like:

    properties ( PCTGetSet, PCTConstraint='string' )
    properties ( PCTGetSet, PCTConstraint='callback' )
    properties ( PCTGetSet, PCTConstraint='logicalscalar|presubmission' )

    For example, refer to the file: which -all parallel.Task

    In this case I don’t think this is just a case of undocumented language syntax. I am starting to think that there is a way to define your own custom property attributes on classes and have them do stuff like type checking, much like matlab.System system objects or Simulink data classes.

    Unfortunately several classes which others derive from are either protected as p-code files or implemented as builtins… So more digging is needed 😉

  5. Jim Hokanson says:

    This is an exciting move by TMW to start to allow easy, optional ways of strictly defining property types. What wasn’t immediately clear from a quick skim of the post (but was in fact present on further review), was that you can apply class definitions to this approach as well

    properties
       my_prop@my_second_class
    end

    I recently posted an enhancement request asking TMW to allow the editor to assume that the first input to a method is an instance of the class. This would significantly enhance tab complete functionality. The workaround is to first enter the method and to do all of the programming in debug mode where Matlab can tell what all the variables are.
    They politely informed me that the first variable is not always an object instance due to inferior/superior relations (Useful for operator methods like +,*,| etc). I think having tab complete be wrong 1% (0.00001%?) of the time would be fine, given the enhancement and the fact that it is tab complete, not code execution.

    Back to this post, if an object instance can now be inferred from the object method, and we can specify properties as belonging to classes, then it would be possible to tab complete the property as well!

    my_obj_instance.my_prop.[tab]!

    Switching topics …
    As those that commonly use OOP in Matlab know, their design is rapidly evolving. This also includes a large host (IMHO) of bugs that have yet to be fixed, or that are fixed and make backwards compatibility difficult.

    This undocumented feature is not immune. In my testing, assignment of a numeric scalar to a property that is defined as a class type is allowed.

    From code bit above:

    my_prop = my_second_class; %Correct
    my_prop = some_different_class; %Throws an error
    my_prop = 1; %No error :/
    • Donn Shull says:

      This numerical argument “bug” may be intentional since The MathWorks frequently uses numeric handles for classes.

    • Jim Hokanson says:

      Apparently this only occurs in limited cases. The example I noticed it in was assignment in the constructor which is followed by more property assignments within the constructor.

  6. Chris Hoogeboom says:

    Wow, This is a great find, and will save me so much time! Thanks a lot!

  7. Sam P says:

    Do you have any experience with using this kind of undocumented feature for production code? Does “undocumented” imply “unsupported” in your experience? This kind of thing is super useful, but will it last the next 10 releases?

    • Yair Altman says:

      @Sam – undocumented indeed means unsupported in most cases. What this means in practice is that we are allowed to use these features, but if you find a bug or encounter problems you should not expect MathWorks to help you (they might but they do not have to). Everything in this blog abides by the license agreement as far as I know (note that I am an engineer, not a lawyer), so AFAIK there is no legal question, only a question of supportability. You may use these features as you see fit, but only on an as-is basis, without any warranty or support of any kind.

      I know of many people/firms who use these features in production system, but I also know many who only use fully-documented/supported stuff – the choice is entirely yours.

      As for the next 10 releases I have absolutely no idea. I do not believe that even MathWorks have a detailed roadmap so far into the future. Many of these features have remained as-is for the past 10 releases, but nobody can promise they will remain. Some of them may be removed in the very next release, or in 5 years, or never. As long as you stay with your current release in your production system and retest thoroughly whenever you upgrade the Matlab release, then you should be ok (after all, you can always remove the extra features if something starts to break in the future).

      Having said that, I try to label my articles in one of three categories based on my personal subjective gut feeling on their presumed risk of failing in some future Matlab release. Hover your mouse over the low/medium/high category links in the Categories list on the right of this page to see a detailed description of what the different levels mean. This may help you make a personal decision on which features to use in your system. Just note that I base my labeling on gut feeling, not on any insider information (I am independent of MathWorks). My personal subjective labeling of this article was “Medium risk of breaking in a future release“.

  8. Martin Lechner says:

    That are great news for me.

    I tried to add scalar behind the type of the property. This restricts the values to scalar values and also works for user defined classes. This saves me a lot of type checks.
    Thanks, Martin

    properties
       val@double scalar
       val2@pack.subpack.UserClass scalar
    end
    • Sebastian Hölz says:

      Interesting …

      I took a look into some examples in the Matlab installation and found several examples. The general syntax seems to be:

      properties
         val@classname dimension = value
      end

      classname can be anything like double, single, UserClass etc. and dimension can be scalar, vector, matrix. As last input the property may also be initiated with a value.

      Maybe there is a way to prevent empty values, infinity, … I don’t know, but maybe someone else does.

      Cheers

      Sebastian

    • Yair Altman says:

      @Sebastian – thanks for the clarification, I updated the main article text accordingly.

    • Sebastian Hölz says:

      Yair states that ” … Note that setting the type as above seems to override any set method that may have been specified for the property.”. I can not confirm this for the above syntax (tested in Matlab 2011b and 2013a). Property-set functions are called as expected.

  9. Sumaia says:

    I have a question in MATLAB and still a student
    use matlab to design a 3_tap fir low pass filter with a cutoff frequency of 800HZ and sampling rate 8000HZ usin
    Rectangular window
    Triangular window
    Hanning window
    Blackman window

    • Yair Altman says:

      @Sumaia – this is not a general Matlab forum, but a website dedicated to specific advanced Matlab topics. In any case, we do not solve homework assignments here.

      Good luck in your studies. Do visit again when you become proficient enough with Matlab to benefit from the articles here.

  10. Jaxor24 says:

    Finally! This will save me a lot of type checking. One (perhaps obvious) thing I’ve noticed is that when
    properties are UserClass vectors you need to use .empty() to manually initialize.
    e.g.

    properties
    listOfObjects@UserClass
    end

    You will need to call

    listOfObjects.empty

    to ‘reset’ the object, rather than

    listOfObjects = []
    • Toea says:

      The fact that for user classes we need to use

      listOfObjects.empty

      instead of

      listOfObjects = []

      prevent us to remove an element in a list using for example

      listOfObjects(id) = []

      It takes me hours to understand what was wrong in my delete method!!

      Do you think there is a way to remove easily an element when you use this undocumented features?

    • Jan says:

      @Toea: I don’t quite understand the problem. In my 2013b the assignment

      methods
         function deleteFirst(self)
            self.listOfObjects(1) = [];
         end
      end

      worked just as expected. Otherwise:

      methods
         function deleteFirst(self)
            self.listOfObjects(1) = UserClass.empty();
         end
      end

      works just as well, as long as UserClass is not abstract.

  11. Pingback: More on Typing Systems | Matlab Love!

  12. Pingback: Class object tab completion & improper field names | Undocumented Matlab

  13. ola says:

    Is there any way of introspect this type restriction? findproperty doesn’t seem to reveal it unfortunately…

    • Yair Altman says:

      @Ola – I do not know of a direct way, but perhaps there is a way. Anyway, if the property happens to have a default value you can get its type:

      >> classDef = ?Packet;  % or: metaclass(Packet)
      >> payloadLengthProp = classDef.PropertyList(2);  % simpler for handle classes: findprop(object,propName)
      >> payloadLengthType = class(payloadLengthProp.DefaultValue)
      ans = 
      uint16
    • Martin says:

      There is a way to introspect this, but it was added very recently (R2015a), e.g.:

      mc = ?meta.class
      mc.PropertyList(1).Type
      mc.MethodList(1).InputTypes
      mc.MethodList(1).OutputTypes

      The hidden Type property of the meta.property class holds an instance of the hidden meta.type class (or the equally hidden meta.EnumeratedType for certain properties of graphics classes). No restriction on the type is expressed with a type name of any.

      The hidden InputTypes and OutputTypes properties of the meta.method class are just cell arrays of strings containing the type names. (I’m not aware of a way to express this restriction on input and output arguments in pure MATLAB code, so this information seems to be only helpful for built-in methods.)

  14. Erich Ritz says:

    Warning! MATLAB 2015b crashes when referencing class properties defined as scalar using this method, if those properties are also Constant properties. I reported this to The MathWorks and the response is their development team is actively investigating to fix this issue, which may be included in future releases. In the meantime, remove the use of the undocumented type syntax or downgrade to R2015a.

    classdef TestDataClass
        properties (Constant)
            x@double scalar = 1;
        end
    end

    This will crash:

    testData = TestDataClass;
    testData.x
  15. PYC says:

    Very useful feature Yair! Unfortunately, I still cannot exploit it to its full potential, since I would like to specify that a property be a complex double scalar. If I use the syntax var@double scalar, then Matlab will only allow me to assign real values to var.

    I have tried a number of ways to find the correct syntax. For example, http://www.mathworks.com/help/simulink/ug/simulink-data-class-extension-using-matlab-class-syntax.html does not cover complex variables. Also, you can ask Matlab to tell you the variable type using the class() function, but this doesn’t distinguish between real and complex double floats. Lastly, the workspace panel says the type is “double (complex)”, but I have not been able to discover from this the correct syntax to use.

    Do you have any ideas? Or perhaps this is simply impossible.

    • Simply add the “complex” attribute:

      classdef test_mcos
          properties
              value@double scalar complex = 1 + 2i
          end
      end
       
      >> t = test_mcos
      t = 
        test_mcos with properties:
          value: 1 +    2i
  16. Adam Gogacz says:

    Thanks for this Yair. I’ve used this approach in the past. However, as of 2016a MATLAB has a documented way of casting the property value.

    http://www.mathworks.com/help/matlab/matlab_oop/defining-properties.html

  17. Marshall says:

    Is there a way to specify that a property must be of a subclass type? For example, the following is not allowed:

    configset@Simulink.ConfigSet scalar;

    The ‘.’ in there messes up the syntax parser, and I can’t figure out how to get around this.

    • @Marshall – perhaps you can create a new class that inherits Simulink.ConfigSet and adds nothing to it, whose only benefit is the fact that it does not have a dot in its class name:

      classdef Simulink_ConfigSet < Simulink.ConfigSet
      end

      Then you can simply use the new class name:

      configset@Simulink_ConfigSet scalar

Leave a Reply


Your email address will not be published. Required fields are marked *