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 *)
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.
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.
A function can have more than one return statement, but only ever run one based on a condition.
A function can have any number of return statements.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With