Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Do/Return behave differently in Compile -- why?

I am wondering if this is a bug or a documented behaviour?

f1 = Function[v, 
  Do[If[v[[i]] < 0, Return[v[[i]]]], {i, 1, Length[v]}]]

c1 = Compile[{{v, _Integer, 1}}, 
  Do[If[v[[i]] < 0, Return[v[[i]]]], {i, 1, Length[v]}]]

When applying them to a list containing no negative numbers, we get different results:

In[66]:= Through[{f1, c1}[{1, 2, 3}]]

Out[66]= {Null, 3}

This has caused a bug when I tried to compile a short function (actually a modified version of it).

Do alone doesn't show the problem:

c2 = Compile[{}, Do[i, {i, 5}]]

c2[] (* returns nothing, as expected *)
like image 369
Szabolcs Avatar asked Nov 18 '11 15:11

Szabolcs


People also ask

What two effects does a return statement have on the behavior of a function?

A return statement ends the execution of a function, and returns control to the calling function. Execution resumes in the calling function at the point immediately following the call. A return statement can return a value to the calling function. For more information, see Return type.

Can a function be compiled without a return statement?

In other words, a return call can also be used to terminate procedures and anonymous code blocks without returning a value (as a function would) to the caller. So this is why a function will compile without an error when missing a return.

Can you have 2 return statements?

A function can have more than one return statement, but only ever run one based on a condition.

Can you have 2 return statements in C++?

A function can have any number of return statements.


2 Answers

I'd say this a bug with the way Compile is working, but it's not terribly surprising that it isn't working right. Compile does make pretty specific assumptions about not only its inputs (here, that v will be a list of integers) but also its outputs. Compiled functions are supposed to return values that of a single, specific type, and that type must be one of the types that's acceptable as an input for a compiled function: True|False, Integer, et c., and arrays of the same. It would obviously be better if the function complained with a message and then returned Null, but in order to be a well-behaved function for compilation, you need to provide an appropriate integer return value as a defalult.

EDIT to clarify about output types, per Szabolcs' comment below.

like image 166
Pillsy Avatar answered Sep 27 '22 20:09

Pillsy


I would not say this is a bug. As @Pillsy noted, Compile-d function is more restricted since it has to always return the same type. Since Do is a scoping construct, the Return inside Do only breaks out of Do, not Function. Therefore, in some cases it returns a vector element, in others it returns Null. Strictly speaking, as written, the function should not compile at all. However, one can be more flexible and assume that the writer of the function knows better, and will discard the answer in that particular case. With this interpretation, Compile is free to produce any answer in that case. What it does here is to produce the last element in the list. And I think, this is no more ad-hoc than producing a fixed number every time. I also think that such corner cases can not be avoided when a much more flexible symbolic code is compiled. Compile could have had more strict rules in this case and require some meaningful return (of the same type) in all cases, but it is not clear to me whether this would really be beneficial. In a sense, all C is like that - the compiler assumes that you know what you are doing, but allows you to create a lot of undefined behavior if you are not careful.

like image 32
Leonid Shifrin Avatar answered Sep 27 '22 20:09

Leonid Shifrin