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 asdouble
,single
, orUserClass
dimensionType
can be one of the following terms:scalar
,vector
, ormatrix
- 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 |
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 endend |
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 |
Addendum September 30, 2022: Matlab R2022a has made the legacy @ syntax unsupported, displaying an error message about it in the Matlab Editor, and generating a run-time error if you try to use a class that uses this syntax.
For users with Simulink there is a documented way for setting a few data types on properties using the PropertyType qualifier. Examples include
and
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.
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.
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.
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
@Kristian – interesting: Do you remember where you had first learned of this syntax?
Thanks for the mention. I’m glad to have been able to contribute at least the “boring” example to your great blog 🙂
@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… 🙂
@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:
with:
@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:
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 😉
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!
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:
This numerical argument “bug” may be intentional since The MathWorks frequently uses numeric handles for classes.
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.
Wow, This is a great find, and will save me so much time! Thanks a lot!
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?
@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“.
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
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
@Sebastian – thanks for the clarification, I updated the main article text accordingly.
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.
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
@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.
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
The fact that for user classes we need to use
listOfObjects.empty
instead of
prevent us to remove an element in a list using for example
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?
@Toea: I don’t quite understand the problem. In my 2013b the assignment
worked just as expected. Otherwise:
works just as well, as long as
UserClass
is not abstract.[…] I came across this article from the blog Undocumented Matlab. It basically shows a way to define a type for each of the […]
[…] a different way to constrict property data type […]
Is there any way of introspect this type restriction? findproperty doesn’t seem to reveal it unfortunately…
@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:
There is a way to introspect this, but it was added very recently (R2015a), e.g.:
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.)
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.
This will crash:
testData = TestDataClass; testData.x
thanks for reporting this Erich
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:
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
@Adam – see my response in detail here: http://undocumentedmatlab.com/blog/setting-class-property-types-2
I agree with your point. I can think of many simple solutions to type-specification without breaking users’ code all the while sticking to the convention of having the type to the left of the variable. For example, specifying the type in brackets to the left of the property (i.e. myProp), or a thousand other ways. Another lacking feature is the ability to specify type when adding a property dynamically via “addprop”.
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:Then you can simply use the new class name:
The undocumented syntax, e.g.
runs fine in R2019a, but produces a warning in R2019b:
For what its worth, I am still getting that same “undocumented syntax” warning in 2022a. I really hope they don’t create another breaking change…
Starting in R2022b the legacy @ syntax has changed from a warning to an error. Classes that use the legacy syntax generate a run-time error and no longer run.
Now you can use arguments validation block