Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Function call evaluation order varies more than manual allows #6136

Closed
vicuna opened this Issue Aug 22, 2013 · 2 comments

Comments

Projects
None yet
1 participant
@vicuna
Copy link
Collaborator

vicuna commented Aug 22, 2013

Original bug ID: 6136
Reporter: @yallop
Status: closed (set by @mshinwell on 2016-12-13T10:45:30Z)
Resolution: duplicate
Priority: normal
Severity: minor
Target version: 4.03.1+dev
Category: documentation
Related to: #7346
Monitored by: @ygrek @hcarty @xavierleroy

Bug description

The manual says that OCaml application is multi-argument

The expression expr argument1 … argumentn evaluates the expression expr and
those appearing in argument1 to argumentn.

and that the order of evaluation of the arguments and the function is
unspecified:

The order in which the expressions expr, argument1, …, argumentn are
evaluated is not specified.

However, the time of the actual call is specified: it takes place after the
function expression and all the argument expressions have been evaluated:

The expression expr must evaluate to a functional value f, which is then
applied to the values of argument1, …, argumentn.

In practice, there's more variation in the behaviour; it shows up when a
function performs an effect after receiving arguments. Here's an example
showing the different behaviour between ocamlc and ocamlopt, and with known
and unknown functions:

First, the example. (The function syntactically takes two arguments, but its
type 'a -> 'b -> 'a allows more.)

$ cat call.ml
let f g x = ignore (failwith "called f"); g

let g x = x

let h = f g 2 (failwith "third argument")

With ocamlc the function is never called, since the evaluation of the third
argument raises an exception:

$ ocamlc call.ml -o call && ./call
Fatal error: exception Failure("third argument")

With ocamlopt the function is called before receiving all three arguments, so
the third argument is never evaluated:

$ ocamlopt call.ml -o call && ./call
Fatal error: exception Failure("called f")

Here's a variation of the example where f is no longer statically visible:

$ cat call2.ml
let f g x = ignore (failwith "called f"); g

let g x = x

let h f =
f g 2 (failwith "third argument")

let _ = h f

Now ocamlopt evaluates all three arguments before calling the function:

$ ocamlopt call2.ml -o call2 && ./call2
Fatal error: exception Failure("third argument")

@vicuna

This comment has been minimized.

Copy link
Collaborator Author

vicuna commented Aug 22, 2013

Comment author: @damiendoligez

Simplifying the examples a little bit:

let pr x = Printf.printf "%s\n%!" x;;
let f = fun x -> ignore (pr "f"); fun y -> ();;
f (pr "1") (pr "2");;

With ocamlc, we get the expected "2 1 f"; with ocamlopt, we get "1 f 2".

@vicuna

This comment has been minimized.

Copy link
Collaborator Author

vicuna commented Dec 13, 2016

Comment author: @mshinwell

Superceded by #967

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.