Reputation: 1264
Are there enumerated types in MATLAB? If not, what are the alternatives?
Upvotes: 44
Views: 43943
Reputation: 125864
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:
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.
Upvotes: 18
Reputation: 3323
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.
Upvotes: 28
Reputation: 74940
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
Upvotes: 46
Reputation: 79
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
Upvotes: 7
Reputation: 3628
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
// the enum "MyAlerts" in c# will look something like this
public enum MyAlerts
{
value_1 = 0,
value_2 = 1,
MyAlerts_Count = 2,
}
Upvotes: 1
Reputation: 1743
If you have access to the Statistics Toolbox, you might consider using a categorical object.
Upvotes: 4
Reputation: 7961
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
Upvotes: 3
Reputation: 23858
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:
Downsides:
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'.
Upvotes: 5
Reputation: 23858
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
Upvotes: 7