How do I create enumerated types in MATLAB?
Asked Answered
F

10

44

Are there enumerated types in MATLAB? If not, what are the alternatives?

Fredricfredrick answered 7/9, 2009 at 11:58 Comment(0)
O
28

You can get some of the functionality with new-style MATLAB classes:

classdef (Sealed) Colors
    properties (Constant)
        RED = 1;
        GREEN = 2;
        BLUE = 3;
    end

    methods (Access = private)    % private so that you cant instantiate
        function out = Colors
        end
    end
end

This isn't really a type, but since MATLAB is loosely typed, if you use integers, you can do things that approximate it:

line1 = Colors.RED;
...
if Colors.BLUE == line1
end

In this case, MATLAB "enums" are close to C-style enums - substitute syntax for integers.

With the careful use of static methods, you can even make MATLAB enums approach Ada's in sophistication, but unfortunately with clumsier syntax.

Osmond answered 7/9, 2009 at 22:58 Comment(3)
Just be aware of possible performance hits when using the new object oriented stuff. In my experience, it introduced a significant overhead. It really depends on what you're doing, however.Bibliofilm
Actually, for simple classes, there is effectively no time penalty compared to using lots of global structs. However, the development time savings for good practices is substantial, and rarely is runtime such a problem. Hardware's cheap. The people writing the software aren't.Osmond
See below for the Now-standard Enumeration keyword. That is the better answer now.Osmond
N
45

Starting from R2010b, MATLAB supports enumerations.

Example from the documentation:

classdef Colors
   properties
      R = 0;
      G = 0;
      B = 0;
   end

   methods
      function c = Colors(r, g, b)
         c.R = r; c.G = g; c.B = b;
      end
   end

   enumeration
      Red   (1, 0, 0)
      Green (0, 1, 0)
      Blue  (0, 0, 1)
   end
end
Nicholas answered 6/11, 2010 at 2:58 Comment(3)
for future readers, this probably should be the accepted answer (all good solutions nonetheless)Frisse
This is a more complicated example of the enum class. A simpler one can be found within the documentation.Costard
Url for the simpler example @KronoS mentioned: linkDihybrid
O
28

You can get some of the functionality with new-style MATLAB classes:

classdef (Sealed) Colors
    properties (Constant)
        RED = 1;
        GREEN = 2;
        BLUE = 3;
    end

    methods (Access = private)    % private so that you cant instantiate
        function out = Colors
        end
    end
end

This isn't really a type, but since MATLAB is loosely typed, if you use integers, you can do things that approximate it:

line1 = Colors.RED;
...
if Colors.BLUE == line1
end

In this case, MATLAB "enums" are close to C-style enums - substitute syntax for integers.

With the careful use of static methods, you can even make MATLAB enums approach Ada's in sophistication, but unfortunately with clumsier syntax.

Osmond answered 7/9, 2009 at 22:58 Comment(3)
Just be aware of possible performance hits when using the new object oriented stuff. In my experience, it introduced a significant overhead. It really depends on what you're doing, however.Bibliofilm
Actually, for simple classes, there is effectively no time penalty compared to using lots of global structs. However, the development time savings for good practices is substantial, and rarely is runtime such a problem. Hardware's cheap. The people writing the software aren't.Osmond
See below for the Now-standard Enumeration keyword. That is the better answer now.Osmond
L
18

If you want to do something similar to what Marc suggested, you could simply make a structure to represent your enumerated types instead of a whole new class:

colors = struct('RED', 1, 'GREEN', 2, 'BLUE', 3);

One benefit is that you can easily access structures in two different ways. You can specify a field directly using the field name:

a = colors.RED;

or you can use dynamic field names if you have the field name in a string:

a = colors.('RED');

In truth, there are a few benefits to doing what Marc suggested and creating a whole new class to represent an "enum" object:

  • You can control how the object is modified.
  • You can keep the definition in one place and easily use it in multiple places.
  • You can control failures and make them more "graceful", like returning an empty matrix if you try to access a non-existent field (as opposed to throwing an error).

However, if you don't need that sort of complexity and just need to do something quick, a structure is likely the easiest and most straight-forward implementation. It will also work with older versions of MATLAB that don't use the newest OOP framework.

Lueluebke answered 8/9, 2009 at 15:31 Comment(0)
H
7

You could also use Java enum classes from your Matlab code. Define them in Java and put them on your Matlab's javaclasspath.

// Java class definition
package test;
public enum ColorEnum {
    RED, GREEN, BLUE
}

You can reference them by name in M-code.

mycolor = test.ColorEnum.RED
if mycolor == test.ColorEnum.RED
    disp('got red');
else
    disp('got other color');
end

% Use ordinal() to get a primitive you can use in a switch statement
switch mycolor.ordinal
    case test.ColorEnum.BLUE.ordinal
        disp('blue');
    otherwise
        disp(sprintf('other color: %s', char(mycolor.toString())))
end

It won't catch comparisons to other types, though. And comparison to string has an odd return size.

>> test.ColorEnum.RED == 'GREEN'
ans =
     0
>> test.ColorEnum.RED == 'RED'
ans =
     1     1     1
Herbivorous answered 9/9, 2009 at 21:49 Comment(0)
S
7

There is actually a keyword in MATLAB R2009b called 'enumeration'. It seems to be undocumented, and I cannot say I know how to use it, but the functionality is probably there.

You can find it in matlabroot\toolbox\distcomp\examples\+examples

classdef(Enumeration) DmatFileMode < int32

    enumeration
        ReadMode(0)
        ReadCompatibilityMode(1)
        WriteMode(2)
    end
<snip>
end
Scotty answered 31/10, 2009 at 8:56 Comment(1)
This is the correct way to do it if you will perform code generation. It is documented better in the Simulink documentation under "Defining an Enumerated Data Type."Verniavernice
H
5

You could make a Matlab class that behaves like a Java's old typesafe enum pattern. A modification of Marc's solution could take it from C-style typedefs to more like Java-style typesafe enums. In this version, the values in the constants are typed Color objects.

The upsides:

  • The type can be checked (at runtime) by == and other operations to prevent accidental comparison to raw numerics or other types of enums.
  • You can explicitly check the type of your variables (at runtime).
  • Values are displayed with readable names instead of the opaque codes.
  • Operations like mean() and std() that don't make sense on enums are disallowed.

Downsides:

  • Longer class definition. But, this is all boilerplate, and can be reused for any other enum class, changing just the class name and Constant properties.
  • These enums cannot be used directly in switch blocks. Need to pop the Code out, which loses some type safety.
  • Objects will be slower than primitives. Relevant if you're using constants inside loops.

On the whole, I don't know which approach is better. Haven't used either in practice.

classdef (Sealed) Color
%COLOR Example of Java-style typesafe enum for Matlab

properties (Constant)
    RED = Color(1, 'RED');
    GREEN = Color(2, 'GREEN');
    BLUE = Color(3, 'BLUE');
end
properties (SetAccess=private)
    % All these properties are immutable.
    Code;
    Name;
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
methods (Access = private)
%private so that you can't instatiate directly
    function out = Color(InCode, InName)
        out.Code = InCode;
        out.Name = InName;
    end       
end
methods (Static = true)
    function needa(obj)
    %NEEDA Asserts that obj must be a Color
        if ~isa(obj, mfilename)
            error('Input must be a %s; got a %s', mfilename, class(obj));
        end
    end
end
methods (Access = public)
    function display(obj)
      disp([inputname(1) ' =']);
      disp(obj);
    end
    function disp(obj)
        if isscalar(obj)
            disp(sprintf('%s: %s (%d)', class(obj), obj.Name, obj.Code));
        else
            disp(sprintf('%s array: size %s', class(obj), mat2str(size(obj))));
        end
    end    
    function out = eq(a, b)
        %EQ Basic "type-safe" eq
        check_type_safety(a, b);
        out = [a.Code] == [b.Code];
    end
    function [tf,loc] = ismember(a, b)
        check_type_safety(a, b);
        [tf,loc] = ismember([a.Code], [b.Code]);
    end
    function check_type_safety(varargin)
        %CHECK_TYPE_SAFETY Check that all inputs are of this enum type
        for i = 1:nargin
            if ~isa(varargin{i}, mfilename)
                error('Non-typesafe comparison of %s vs. %s', mfilename, class(varargin{i}));
            end
        end
    end
end
end

Here's a function to exercise it.

function do_stuff_with_color(c)
%DO_STUFF_WITH_COLOR Demo use of the Color typesafe enum

Color.needa(c); % Make sure input was a color
if (c == Color.BLUE)
    disp('color was blue');
else
    disp('color was not blue');
end

% To work with switch statements, you have to explicitly pop the code out 
switch c.Code
    case Color.BLUE.Code
        disp('blue');
    otherwise
        disp(sprintf('some other color: %s', c.Name));
end

Example of use:

>> Color.RED == Color.RED
ans =
     1
>> Color.RED == 1
??? Error using ==> Color>Color.check_type_safety at 55
Non-typesafe comparison of Color vs. double

Error in ==> Color>Color.eq at 44
        check_type_safety(a, b);

>> do_stuff_with_color(Color.BLUE)
color was blue
blue
>> do_stuff_with_color(Color.GREEN)
color was not blue
some other color: GREEN
>> do_stuff_with_color(1+1) % oops - passing the wrong type, should error
??? Error using ==> Color>Color.needa at 26
Input must be a Color; got a double

Error in ==> do_stuff_with_color at 4
Color.needa(c); % Make sure input was a color

>> 

A minor quirk in both approaches: the C convention of putting the constant on the left hand of the "==" to prevent bad assignment doesn't help as much here. In Matlab, if you accidentally use "=" with this constant on the LHS, instead of an error, it'll just create a new local struct variable named Colors, and it will mask the enum class.

>> Colors.BLUE = 42
Colors = 
    BLUE: 42
>> Color.BLUE = 42
Color = 
    BLUE: 42
>> Color.RED
??? Reference to non-existent field 'RED'.
Herbivorous answered 9/9, 2009 at 21:26 Comment(0)
G
4

If you have access to the Statistics Toolbox, you might consider using a categorical object.

Ginkgo answered 9/9, 2009 at 20:46 Comment(0)
K
3

After trying out the other suggestions on this page, I landed on Andrew's fully object-oriented approach. Very nice - thanks Andrew.

In case anyone is interested, however, I made (what I think are) some improvements. In particular, I removed the need to double-specify the name of the enum object. The names are now derived using reflection and the metaclass system. Further, the eq() and ismember() functions were re-written to give back properly-shaped return values for matrices of enum objects. And finally, the check_type_safety() function was modified to make it compatible with package directories (e.g. namespaces).

Seems to work nicely, but let me know what you think:

classdef (Sealed) Color
%COLOR Example of Java-style typesafe enum for Matlab

properties (Constant)
    RED = Color(1);
    GREEN = Color(2);
    BLUE = Color(3);
end
methods (Access = private) % private so that you can''t instatiate directly
    function out = Color(InCode)
        out.Code = InCode;
    end       
end


% ============================================================================
% Everything from here down is completely boilerplate - no need to change anything.
% ============================================================================
properties (SetAccess=private) % All these properties are immutable.
    Code;
end
properties (Dependent, SetAccess=private)
    Name;
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
methods
    function out = eq(a, b) %EQ Basic "type-safe" eq
        check_type_safety(a, b);
        out = reshape([a.Code],size(a)) == reshape([b.Code],size(b));
    end
    function [tf,loc] = ismember(a, b)
        check_type_safety(a, b);
        [tf,loc] = ismember(reshape([a.Code],size(a)), [b.Code]);
    end
    function check_type_safety(varargin) %CHECK_TYPE_SAFETY Check that all inputs are of this enum type
        theClass = class(varargin{1});
        for ii = 2:nargin
            if ~isa(varargin{ii}, theClass)
                error('Non-typesafe comparison of %s vs. %s', theClass, class(varargin{ii}));
            end
        end
    end

    % Display stuff:
    function display(obj)
        disp([inputname(1) ' =']);
        disp(obj);
    end
    function disp(obj)
        if isscalar(obj)
            fprintf('%s: %s (%d)\n', class(obj), obj.Name, obj.Code);
        else
            fprintf('%s array: size %s\n', class(obj), mat2str(size(obj)));
        end
    end    
    function name=get.Name(obj)
        mc=metaclass(obj);
        mp=mc.Properties;
        for ii=1:length(mp)
            if (mp{ii}.Constant && isequal(obj.(mp{ii}.Name).Code,obj.Code))
                name = mp{ii}.Name;
                return;
            end;
        end;
        error('Unable to find a %s value of %d',class(obj),obj.Code);
    end;
end
end

Thanks, Mason

Kent answered 13/7, 2010 at 17:56 Comment(0)
T
2
Toys = {'Buzz', 'Woody', 'Rex', 'Hamm'};

Toys{3}
  ans = 'Rex'
Trustworthy answered 1/4, 2013 at 20:21 Comment(0)
H
1

If you need the enumerated types just for passing to C# or .NET assembly, you can construct and pass the enums with MATLAB 2010:

A = NET.addAssembly(MyName.dll)
% suppose you have enum called "MyAlerts" in your assembly
myvar = MyName.MyAlerts.('value_1');

you can also check the official MathWorks answer at

How do I use .NET enumerated values in MATLAB 7.8 (R2009a)?

// the enum "MyAlerts" in c# will look something like this
public enum MyAlerts
{
    value_1 = 0,
    value_2 = 1,
    MyAlerts_Count = 2,
}
Hosier answered 16/3, 2011 at 15:27 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.