3

If I include a continue as a parameter of an eval() instruction, it does not work as expected. For example, when executing the following code:

listParam = {'a','b','c'};
a = 17;
b = NaN;
c = 4;

for ii=1:numel(listParam),
    eval(['if isnan(',listParam{ii},'), continue; end']);
    disp(['The parameter ', listParam{ii}, ' is not a NaN.']);
end

It will prompt the error:

Error: A CONTINUE may only be used within a FOR or WHILE loop.

Anybody knows why?

Note: I know that I should avoid eval() and the previous example could be refactored in a much better coding; but I found a weird behaviour and I am curious what is happening.

tashuhka
  • 5,028
  • 4
  • 45
  • 64

2 Answers2

3

The expression you pass to eval must be a valid matlab expression on it's own, any surrounding code is not considered. This means each continue must be surrounded by a loop. Either put the surrounding for within your eval or put the continue outside.

Daniel
  • 36,610
  • 3
  • 36
  • 69
  • +1 Any reference about the fact that the argument to `eval` is evaluated independent of "normal" code? – Luis Mendo Aug 12 '14 at 22:06
  • I updated my answer to precise it. @LuisMendo: I don't have any reference, but to my understanding the code is simply not a valid expression. – Daniel Aug 13 '14 at 00:20
  • 2
    @LuisMendo Concerning the scope of `eval`, I took some simple experiments; if one puts `continue` in a separate `foo.m` script (with a single line saying `continue`), and in main script uses `eval('foo')`, the `for` loop will get controlled. – Yvon Aug 13 '14 at 01:33
  • @Yvon That's interesting! – Luis Mendo Aug 13 '14 at 11:19
2

As @Daniel has pointed out, eval is called by the script, while it is not directly controlled by the for loop. You can think it as: the continue in eval would move the program counter to the head of the code inside eval, but not that of the for loop; this of course would fail, as Matlab does not allow jumping between lines.

A continue can only appear directly inside a for or while loop. However, you can hack the code like this:

for ii=1:numel(listParam),
    eval(['if isnan(',listParam{ii},'), x=1; else, x=0; end']);
    if x
        continue;
    end
    disp(['The parameter ', listParam{ii}, ' is not a NaN.']);
end

Strangely, x happens to appear in the script's stack. However, this is far from a good piece of code. Never use this method.


Edit: about the "control" scope of eval.

I'm not talking about the variable scope / workspace of eval. Hints can be found in several documentations like this and this. In short, eval uses the "current" workspace.

However, I found the following things interesting:

  1. Running continue directly in eval

    for ii = 1:2
        eval('continue')
        ii+10
    end
    

    This simply fails, as shown in the question. The error is Error: A CONTINUE may only be used within a FOR or WHILE loop. which means the continue inside eval cannot find any loop (the for loop).

  2. Calling a separate script in a for loop

    for ii = 1:2
        foo
        ii+10
    end
    

    while script foo.m is

    ii
    continue
    

    First of all, in foo.m Mlint gives a red-line warning, which usually indicates an error that can stop the code from running, saying that CONTINUE is only valid in a FOR or WHILE loop. But pressing F5 on foo.m does not have any problem - in fact running a single continue anywhere does not crash the code.

    Running the main script gives output

    ii =
         1
    ii =
         2
    >> 
    

    ....so foo.m catches the for loop?

  3. eval('foo') - I really don't understand Matlab

    for ii = 1:2
        eval('foo')
        ii+10
    end
    

    The result surprised me a bit.

    ii =
         1
    ans =
        11
    ii =
         2
    ans =
        12
    >> 
    

Thought: eval runs the code in an independent control flow, but shares its workspace with the current one. It is (something but not exactly) like an isolated world model, in which (here in Matlab) different pieces of code can interact with the same set of variables, but cannot interact with each other in the sense of control flow.

Unfortunately, I was unable to find any existing resources as reference to prove this idea.

This does not change my solution: in any case, try to avoid using eval.

Yvon
  • 2,903
  • 1
  • 14
  • 36