Discover MakerZone

MATLAB and Simulink resources for Arduino, LEGO, and Raspberry Pi

Learn more

Discover what MATLAB® can do for your career.

Opportunities for recent engineering grads.

Apply Today

To resolve issues starting MATLAB on Mac OS X 10.10 (Yosemite) visit: http://www.mathworks.com/matlabcentral/answers/159016

Magic strings and numbers in Matlab

Asked by Jan Simon on 24 Jul 2013

Some of Matlab's toolbox functions are affected by magic strings or magic numbers, which are strings or numbers with a deeper meaning besides the normal value. Both are considered as bad programming patters, because they provoke confusions, when the magic keys appear with the normal meaning by accident. See http://en.wikipedia.org/wiki/Anti-pattern

Example 1:

clear('myVariable')
clear('variables')

While the 1st clears the variable myVariable, the later clears all variables. Here 'variables' has a meta-meaning. The problem appears, when 'variables' is an existing variable:

a = 1;
variables = 2;
clear('variables')
disp(a)   % >> 1

Only variables is cleared, which cannot be understood directly when its definition is 1000 lines before.

Example 2:

uicontrol('String', 'default')

This creates a button with the string '' instead of the expected 'default', because this is the magic string to invoke the default value get(0, 'DefaultUIControlString'). The same concerns properties of other graphic objects also, e.g. the 'name' property of figure or the string of uimenu. There is a workaround which allows the user to display 'default': Simply use '\default'. Unfortunately this is doubled magic, because in consequence it is impossible to display the string '\default'. Obviously a bad idea.

Example 3:

Graphic handles are doubles (although gobject of the new R2013a seems, like this is subject to changes?). But then a handle can be confused with data:

a = axes;  % e.g. 0.0048828125
plot(a, 2, '+')

But you cannot draw the point [0.0048828125, 2] by this way, because the 1st input is considered as handle of the parent. Here all possible values of handles are magic. Collisions are very unlikely, but there is no way to avoid them reliably.

Question:

Which functions are concerned by magic values? What are the pitfalls and workarounds?

4 Comments

Jan Simon on 25 Jul 2013

@dpb: Please post this in the answer section.

dpb on 25 Jul 2013

@jan--you think such ruminations are worth of answer? I really hadn't considered it to quite that level...

But, I'll await your judgment and clean up as you think fit...

I will note after thinking about 1) a little more -- it's a case that could be considered

a) A bug--if a variable named 'variables' exists and the argument to clear contains 'variables' then clear also should test for that case and call itself recursively(*) (actually twice should do it); or

b) Programmer's error -- shouldn't name a variable variables. The problem there is that as above there is no definitive grammar table that gives the rules and/or the, as you call them, "magic" strings or numbers. At least in a defined language such as C or Fortran, while there are ample opportunities for programmer to make errors that aren't necessarily catchable by a compiler until runtime or by simply malfunctioning code per intent, there is a complete set of rules by which one can determine whether the code in question is or is not conforming. If, by chance, one finds a case where that isn't so, then there is a defined process by which that "hole" or anomaly or error in the Standard can be addressed and a definitive ruling made on it. AFAIK, there is no equivalent in Matlab to the defined process for the user--TMW does what TMW decides to do.

(*) Of course, this still has the problem then that there would be no way to only delete the variable variables. The root cause comes back again to the issue that one can alias anything (almost) in Matlab and that there is no rule against such name clashes enforceable except by programmer knowledge which gets more and more problematical the more features that are added.

Jan Simon on 30 Jul 2013

This seems to become a one-man tutorial thread as in the early days of this forum.

Jan Simon

Products

No products are associated with this question.

7 Answers

Answer by Jan Simon on 25 Jul 2013
Edited by Jan Simon on 25 Jul 2013

uicontrol's, figure's and uimenu's use these magic strings for properties, which are strings:

   'default', 'remove', 'factory'

Such properties are e.g. 'String', 'Callback', 'Name', 'Tag', etc.

A bullet-proof workaround:

S = input('Input the button string: ', 's');
if any(strcmp(S, {'default', 'remove', 'factory'})
  S = ['\', S];
elseif any(strcmp(S, {'\default', '\remove', '\factory'})
  warning('String "%s" padded to support uicontrol!', S);
  S = [' ', S];
end
uicontrol('String', S);

Such an ugly catching of rare exceptions is a typical effect of magic strings.

When a callback function is called 'default', use the function handle instead of a string:

uicontrol('Callback', @default);

A real solution, not only a workaround, is to strictly avoid using these names as function names or as 'String' property and never allow not controllable user-input as a property. But this can be a limitation, if e.g. the ten most frequent words of an arbitrary text file should be displayed in 10 buttons.

1 Comment

Kelly Kearney on 1 Aug 2013

Same words are magic (and undocumented as such) for the legend command. And using them leads to all sorts of weird results:

 str = {'bar1', 'bar2', 'line1'};
 for iax = 1:4
     subplot(2,2,iax);
     bar(1:10, 10*rand(10,2));
     hold on;
     plot(1:10, 1:10, 'g');
     legstr = str;
     if iax > 1
         legstr{iax-1} = 'default';
     end
     legend(legstr);
     title(sprintf('legend(''%s'',''%s'',''%s'')', legstr{:}));
 end

Discovered that one through experience when trying to plot model results run with default parameters along with some perturbations. Submitted a request in 2010 to add that to the documentation (since I had to contact the Mathworks to learn about the '\default' trick)... looks like it's still undocumented in R2013a.

Jan Simon
Answer by Jan Simon on 30 Jul 2013
Edited by Jan Simon on 1 Aug 2013

I've found a magic character in for the GUIs:

uicontrol('Style', 'listbox', 'Pos', [1,1,100,100], 'String', 'asd|bsd')

Then the bar is used as separator. This does not matter the style 'edit' or 'text', but the same method can be used to separate tick marks:

set(gca, ...
    'XLim', [0, 40], ...
    'XTick', 0:5:40, ...
    'XTickLabel', '0| |10| |20| |30| |40')

[EDITED] To display bars, use a cell string instead. (Thanks, Walter)

1 Comment

Walter Roberson on 30 Jul 2013

If you use a cell array of strings, the bars will not be treated as special.

Jan Simon
Answer by Jan Simon on 30 Jul 2013

Matlab strings do not use a terminator to mark the end, but the C-routines, which are called for IO operations consider char(0) as terminator:

s = char([65, 0, 66])
% >> A B
disp(s)
% >> A B
fprintf('%s\n', s)
% >> A    (in 2009a)
% >> AB   (in 2011b)

This is not pure magic, but a in fprintf the \0 has an additional meta meaning compared to disp.

4 Comments

Walter Roberson on 31 Jul 2013

In the sprintf() case, 0 appears to be special-cased to show up as blank, as char(1) to char(31) show up as empty except for horizontal tab (^I, 9), vertical tab (^K, 11), linefeed (^J, 10), page feed (^L, 12), carriage-return (^M, 13); and backspace (^H, 8) has negative width. Interestingly, vertical tab and page feed show up as half-width compared to null (0)

dpb on 31 Jul 2013

Yes, it seems to be but it's in the display portion of i/o instead of generic is the difference was pointing out.

The half-width thingie is just dependency on font being variable-pitch isn't it?

dpb on 1 Aug 2013

Just to add more consistency to the inconsistencies... :)

Consider

>> sprintf('%s\n',['A' char(0) 'B'])
ans =
A B
>> fprintf('%s\n',['A' char(0) 'B'])
AB
>> fid=fopen('AB.txt','w');
>> fprintf(fid,'%s\n',['A' char(0) 'B']);
>> fid=fclose(fid);
>> type 'AB.txt'

A >>

Three (slight) perturbations; three different results...the char(0) terminated the write before reaching the \n, in the file.

Erratum--the result for the file is a fignewton of type NOT fprintf -- it appears to use the C characteristic of terminating a string on \C. Reading the file w/ fgets shows that all the characters were put into the file as given. But one will have trouble reading the file just written expecting it to be a string/record.

In summary, on further exploration the only difference I can actually find is that between [s|f]printf in appearance to the console.

Jan Simon
Answer by Jan Simon on 1 Aug 2013
Edited by Jan Simon on 1 Aug 2013

From the docs of close:

close name   % Close figure with the specified name
close all    % Close all non hidden figures

Then 'all' is magic: Even when a figure is called 'all', close('all') closes all figures and not only the one with the matching name. This differs from the behavior of clear all, which clears the variable called all only, if it is existing.

0 Comments

Jan Simon
Answer by Jan Simon on 1 Aug 2013

Although the documentation is clear and there is no magic meta meaning of a specific string, something is magic with the save command. There is a surprising large number of problems in the Matlab forums concerning the confusion of:

save filename A
save 'filename' A
save(filename, A)
save('filename', 'A')

And in the next step for the import:

load(filename)
Data = load(filename)
A    = Data.A
A    = load(filename, 'A')

But what could be the reason for the frequent problems? save is one of the very rare Matlab functions, which do not get the inputs as value, but as name of the variable. While this is considered as a bad programming style for eval and assignin, it is the standard for save. Modern Matlab versions accept the '-struct' flag (well done, TMW! Due to the leading '-' this is not a magic string), such that a kind of passing by value happens.

The output of load must be a struct, but when only one variable is saved, this feels like an unexpected level of abstraction.

Nevertheless, no magic here. The documentation is complete. So this remains a job for the forum.

0 Comments

Jan Simon
Answer by Jan Simon on 1 Aug 2013

When legend is used in the form legend('string'), the following names have magic side-effects:

'off', 'toggle', 'hide', 'show', 'boxoff', 'boxon'

A workaround is either to provide the line handle as first input or to use a cellstring to store the names:

h = line(rand(1,10));
legend(h, 'off')   % 'off' appears as name
legend({'hide'});  % 'hide' appears as name

4 Comments

Jan Simon on 9 Aug 2013

I meant the calling with one string like:

legend('boxon');

You cannot use this style to apply the name 'boxon' for a single line. While 'boxon' might be too unusual to be used as a title, 'off', 'hide', or 'show' are less unlikely.

I've tested this with 6.5, R2009a and R2011b, but the general problem becomes even worse when the magic strings change with the version.

But let me repeat the definition of "magic", if this is still not clear:

Strings are magic, when they cause certain programmatic effects, while other strings in exactly the same command are treated as normal strings. Or when 'off' or 'all' are treated differently than 'qhjuast23'.

dpb on 9 Aug 2013

No, what that suggests is that there's an error in trying to put two labels in the legend call when there's only one line in the plot.

Try

plot(1:10)
legend('boxon')
pause(.5)
legend('1')
pause(.5)
legend('boxoff')

and see what happens...

Daniel on 9 Aug 2013

Now I see the magic. It appears to only be magic when it is the first string

plot([1:10; 2:11]')
legend('My Line', 'boxoff')

gives two legend entries, but

 plot([1:10; 2:11]')
 legend('boxoff', 'My Line')

fails to create a legend.

Jan Simon
Answer by Jan Simon on 9 Aug 2013
Edited by Jan Simon on 26 Aug 2013

In sprintf and fprintf the backslash is magic in the format strings, because it is used to make the special characters magic, e.g. '\n' becomes a line break caracter char(10). If you want the backslash to appear, '\\' is required.

This well known escaping works well in many programming languages. The workaround to use \\ to display one \ appears seldom in the forums. But sometimes users did not consider this when strings are provided as variable:

This works fine:

S = 'hello'
fprintf([S, '\n']);

This fails under Windows due to the backslashes in the path:

S = which('plot.m');
fprintf([S, '\n']);

The general solution is not to insert dynamically created strings in athe format string, but to let %s handle the escape characters:

fprintf('%s\n', S);

Equivalent effects appear in error messages:

error(['Cannot open: ', FileName])   % Prone to bad output
error('Cannot open: %s', FileName)

[EDITED] The problem of escape characters in the error message appeared in several 3rd party Matlab toolboxes, which have been developed under Linux. Then porting them to Windows requires to consider the backslashes in the path names.

0 Comments

Jan Simon

Contact us