Loren on the Art of MATLAB

Switching Things Up 22

Posted by Loren Shure,

If you have ever used a switch statement in MATLAB and also used it in C, you might have noticed that the two constructs have different semantics.

Contents

switch in C

In C, you often terminate case statements in switch constructs with a break statement to prevent execution of the code in the case that follows. Omitting the break statement causes the code in the following case to execute. The behavior of switch statements in C is sometimes described as fall through.

switch in MATLAB

There are several major differences between switch statements in MATLAB and C.

  • MATLAB does not have fall through behavior in its switch statements and therefore no break statement is typically required for individual case statementss.
  • MATLAB case statements have another feature that C and many other languages do not have. The expression following case need not be scalar-valued, but can combine several expressions by placing the acceptable expressions in a cell array.
  • If you want to specify behavior for switch expressions that don't match any of the case expressions, use the otherwise branch. In C, use default instead.
  • Expressions for case statements can include strings and numeric expressions, not just integer values. Though you have to be careful using non-integral numbers because of round-off, this flexibility can make the intent of your code more obvious instead of seeing a list of numbers.
  • More on switch in MATLAB

    When we originally were designing switch for MATLAB, we examined much of our own C source code, and we found a huge majority of the case statements terminated in break, hence the no fall-through behavior of MATLAB. This makes the switch statement in MATLAB equivalent to an if-elseif construct. To achieve fall-through behavior in MATLAB, you can specify all the relevant expressions in one case and then conditionally compute values within that section of code.

    Do You Use switch Statements?

    I am curious to hear about your experiences using switch statements in MATLAB. Post your thoughts here.


    Get the MATLAB code

    Published with MATLAB® 7.8

    22 CommentsOldest to Newest

    I love the Matlab switch construct! When I was first learning Matlab about 5 years ago, I found myself with many of these:

    if (…)
    elseif (…)
    elseif (…)
    elseif (…)
    end

    The switch looks so much nicer in the code. This is especially true when cell arrays are used to replace multiple conditional evaluations.

    Related to differences between C and Matlab is the use of for loop. We found the following useful in some of our code:

    a=[1 2 3;4 5 6;7 8 9];
    for I=a;I,end

    It actually cycles through the columns of matrix and is an easy way to implement column-wise operations. One in a long list of undocumented behaviors.

    Sometimes, I miss the fall-through C-like behavior of switch, for instance, when setting default values of input parameters to a function:

     
    function F (a,b,c,d)
    % C-style switch
    switch nargin
    case 0
       a = 1
    case 1
       b = 2
    case 2
       c = 3
    case 3
       d = 4
    end
     

    looks nicer than

     
    function F (a,b,c,d)
    % matlab-style
    if nargin < 4
       d = 1 
       if nargin < 3
          c = 1
          if nargin < 2
             b = 1
             if nargin < 1
                a = 1
             end
          end
       end
    end
     

    Just a thought

    Jos

    We’ve been replacing a lot of big ugly switch statements with containers.Map since that has been added to MATLAB. Typically they are used for translating between item ‘codes’ or ‘tags’ and the corresponding long-form description or other information.

    Yakov
    Thanks for that little tidbit about cycle through the columns of matrix in a for loop. I had not known about that feature. Probably would have used it often if it had.

    Dan

    Loren-
    The reason I like containers.Map for this is primarily a style thing. To me it looks neater and is easier to mentally parse/maintain when all the keys and values are respectively grouped together. Often I’m copying the keys and values from columns of a CSV or XLS file that someone else has made and it makes it really easy to copy and paste them into the M file and then wrap in {}, compared to manually breaking them out into a switch statement. It also makes it easier to do the help text for the function, because when you are done you can copy the list of keys, paste it into the help text, and then Ctrl-R to comment it.


    keys = {
    'a'
    'b'
    'c'
    'd'
    };
    values = {
    1
    2
    3
    4
    };
    map = containers.Map(keys,values);
    key = 'a';
    out = map(key)

    rather than


    key = a;
    switch key
    case 'a'
    out = 1;
    case 'b'
    out = 2;
    case 'c'
    out = 3;
    case 'd'
    out = 4'
    end

    Regards,
    Eric

    I use switch statements quite frequently, and for all sorts of things.

    For example, in my “vivid” colormap [http://www.mathworks.com/matlabcentral/fileexchange/20848], I needed to interpret a string of color characters (like ‘r’ for red, ‘g’ for green, etc.) as 1×3 arrays of type double. To do this I wrote the following code:

     
    clr_mat = zeros(num_clrs,3);
    c = 0;
    for k = 1:num_clrs
        c = c + 1;
        switch lower(input(k))
            case 'r', clr_mat(c,:) = [1 0 0];  % red
            case 'g', clr_mat(c,:) = [0 1 0];  % green
            case 'b', clr_mat(c,:) = [0 0 1];  % blue
            case 'y', clr_mat(c,:) = [1 1 0];  % yellow
            case 'c', clr_mat(c,:) = [0 1 1];  % cyan
            case 'm', clr_mat(c,:) = [1 0 1];  % magenta
            case 'p', clr_mat(c,:) = [1 0 .5]; % pink
            case 'o', clr_mat(c,:) = [1 .5 0]; % orange
            case 'l', clr_mat(c,:) = [.5 1 0]; % lime green
            case 'a', clr_mat(c,:) = [0 1 .5]; % aquamarine
            case 's', clr_mat(c,:) = [0 .5 1]; % sky blue
            case 'v', clr_mat(c,:) = [.5 0 1]; % violet
            case {'k','w'}, clr_mat(c,:) = [.5 .5 .5]; % grayscale
            otherwise, c = c - 1;
        end
    end
    clr_mat = clr_mat(1:c,:);
     

    By the way, in my example, colors can be repeated if desired, and by using the counter “c”, I was able to ignore invalid inputs.

    I sometimes use switch statements in the following (somewhat kludgy) manner:

    switch sprintf('%d %d', logical_test1, logical_test2)
      case '0 0'
      % Do A
      case '0 1'
      % Do B
      case '1 0'
      % Do C
      case '1 1'
      % Do D
    end
    

    This avoid a bunch of nested if statements and is somewhat clearer in my mind than:

    if logical_test1 
       if logical_test2
         % Do D
       else
         % Do C
       end
    else
       if logical_test2
        % Do B
       else
        % Do A
       end
    end
    

    I’m open to suggestion to improve this.

    Kieran-

    You could switch on the combined tests by converting them to “binary”:

    logtest = logtest1*2+logtest1

    switch logtest
       case 0
       case 1
       case 2
       case 3
    end
    

    I don’t know if that’s more readable or less so.

    –Loren

    I have been using Malab for six years and had no idea it had a switch statement. I have always used elseif, which is a more flexible alternative. I think I will probably stick with elseif in a lot of cases.

    In the simplest cases, like Eric, I often replace long switch statements with lookup tables. I didn’t know that Matlab finally ships with a decent map data structure. The old-style way of doing Joe Kirk’s example would be to put the colors in a structure:
    color_table.r = [1 0 0]; % red
    color_table.g = [0 1 0]; % green
    ...
    and then lookup like this:
    clr_mat(c,:) = color_table.(lower(input(k)));One would have to test for field existence or catch exceptions if unknown colors might be requested.

    Of course, which approach to use is a stylistic choice and will depend on the precise situation. The book “Code Complete” has a section on “Using decision tables to replace complicated logic” that is worth considering.

    Rather than Joe, Iain or Eric’s way of doing look-up tables, I like the clarity of cell arrays and the strcmp function:

    color_table = {
    'red',   [1 0 0]
    'green', [0 1 0]
    'blue',  [0 0 1]
    };
    ii = find(strcmp(color_table(:,1), name ));
    clr_mat(c,:) = color_table{ii,2};
    
    

    .

    The problem with containers.Map, in my opinion, is that the key and the value are physically separated. If you want to add one value to the table, you need to edit your function in two places.

    The switch statement really shines when you need to execute different bits of code based on an input, it’s not so useful for a simple table lookup.

    Chris,

    I like your method for some applications.

    In the particular case I showed however, I am doing more than a simple table lookup. Instead, I am trying to take an input string of color characters and build an Mx3 matrix of RGB triplets.

    For example, if someone provides the input ‘rygb’, I want to build the matrix [1 0 0; 1 1 0; 0 1 0; 0 0 1].

    The colors need to be in the correct order, and if someone provides an invalid color character, I want to ignore it.

    To achieve this with your method, I need to do the following:

    color_table = {
        'r',    [1 0 0]     % red
        'g',    [0 1 0]     % green
        'b',    [0 0 1]     % blue
        'y',    [1 1 0]     % yellow
        'c',    [0 1 1]     % cyan
        'm',    [1 0 1]     % magenta
        'p',    [1 0 .5]    % pink
        'o',    [1 .5 0]    % orange
        'l',    [.5 1 0]    % lime green
        'a',    [0 1 .5]    % aquamarine
        's',    [0 .5 1]    % sky blue
        'v',    [.5 0 1]    % violet
        'k',    [.5 .5 .5]  % grayscale
        'w',    [.5 .5 .5]  % grayscale
        };
    
    num_clrs = length(input(:));
    clr_mat = zeros(num_clrs,3);
    c = 0;
    for k = 1:num_clrs
        c = c + 1;
        ii = find(strcmp(color_table(:,1),lower(input(k))));
        if ~isempty(ii)
            clr_mat(c,:) = color_table{ii,2};
        else
            c = c - 1;
        end
    end
    clr_mat = clr_mat(1:c,:);
    if ~isempty(clr_mat)
        clrs = clr_mat
    end
    

    In my opinion, my SWITCH statement is more compact and readable. I may use your method for other things though… :o)

    A not very clearly documented feature of the switch/case construct that I’ve found useful is that it’s much more general than the examples might lead you to believe. All the examples I’ve seen have been of the form:

    switch x
    case v1

    case v2


    end

    where x is a variable or expression, and each of the vi are numeric or string constants or cells arrays comprised thereof.

    But this also works:

    switch true
    case exp1

    case exp2


    end

    where each of the expi are logical expressions. The first that evaluates as true has its branch executed.

    Can you use conditional statments in a switch statment for example:

    switch num
    case num<-2
    disp(‘Num less than -2′)
    otherwise
    disp(‘Error’)
    end

    I like the switch syntax since the code is so easy for most people to read.

    However, I don’t like how it “artificially” drives the McCabe Clclomatic complexity index high. Thus, when I document a function that I’ve written, & include the output from Code Metrics, I have to write some text to discuss why, for example, the complexity index is 14 rather than my target of less than 10.

    In many cases, my co-workers & I look at the function in detail & decide that it is clearer to use the switch-case syntax & accept the higher index rather than dividing the function into sub-functions just to get the index below 10.

    I’m under the impression that using if-ifelse syntax will result in the same complexity index as the switch-case syntax. Yet, the switch-case syntax is usually clear.

    Maybe I need to invent an Oyster Complexity Index that excludes the effect of the switch-case syntax.

    I appreciate Iain’s discussion of decision tables from Code Complete. I browsed thru our copy & see how to implement such a thing in readable code.

    OysterEngineer-

    if-else will result in the same complexity as switch. We often make the same trade-off you do, to keep a switch statement instead of having some very small subfunctions. There is a reason switch drives up the complexity though. The number of possible paths through the code does indeed go up, just as in an if-else situation.

    –Loren

    These postings are the author's and don't necessarily represent the opinions of MathWorks.