18

In the statement:

fooFunc().barFunc(bazFunc());

barFunc() can obviously not execute until both bazFunc() and fooFunc() have completed.

But is the order of execution of fooFunc() and bazFunc() guaranteed?

Related (but different!) question: Order of execution of parameters guarantees in Java?

Community
  • 1
  • 1
bacar
  • 9,761
  • 11
  • 55
  • 75
  • 1
    1st. `fooFunc()`, than `bazFunc()`, at last `barFunc()` – jlordo Dec 05 '12 at 14:03
  • 2
    Arguably, if you need to guarantee the order of execution in a single statement like this, you're doing something wrong. Edit: This is not to say that this isn't a good question or that there isn't a conclusive answer, just that if you find yourself asking this in a practical context, you may want to sniff out the train of thought that led to this line of code. – jonvuri Dec 05 '12 at 14:04
  • @Kiyura what are you saying? The order of execution is definitely guaranteed here. – jlordo Dec 05 '12 at 14:05
  • I do actually agree with @Kiyura - you should avoid writing code like this - but it's worth knowing as subtle bugs can be discovered through knowing this. – bacar Dec 05 '12 at 14:08
  • I would add that compiler/runtime can reorder the executions, as long as the effect is the same. – irreputable Dec 05 '12 at 15:57

4 Answers4

7

The documentation for this is 15.12.4. Run-time Evaluation of Method Invocation

It says "At run-time, method invocation requires five steps. First, a target reference may be computed. Second, the argument expressions are evaluated. Third, the accessibility of the method to be invoked is checked. Fourth, the actual code for the method to be executed is located. Fifth, a new activation frame is created, synchronization is performed if necessary, and control is transferred to the method code."

In the example, fooFunc() is called as part of computing the target reference, and bazFunc() is one of the argument expressions, so fooFunc() must be called first.

Patricia Shanahan
  • 25,849
  • 4
  • 38
  • 75
  • Just to augment this answer - Part 2 of [Section 15.12.4.1. Compute Target Reference (If Necessary)](http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.12.4.1) goes on to clarify: "the expression Primary is evaluated and the result is used as the target reference" (Primary in this case is the production that refers to `fooFunc()`, the object whose method is being called. (Edit: Actually, I may be the only one who was confused here. I thought the "target reference" may have just referred to the method itself. Carry on.) – jonvuri Dec 05 '12 at 14:20
6

The JLS, Java SE 7 Edition has the following example, which says it's fooFunc() before bazFunc(), however I can only find the example - I haven't yet found the associated statement that specifies it:

Example 15.12.4.1-2. Evaluation Order During Method Invocation

As part of an instance method invocation (§15.12), there is an expression that denotes the object to be invoked. This expression appears to be fully evaluated before any part of any argument expression to the method invocation is evaluated. So, for example, in:

class Test2 { 

    public static void main(String[] args) { 
        String s = "one"; 
        if (s.startsWith(s = "two")) 
            System.out.println("oops"); 
    } 
}

the occurrence of s before ".startsWith" is evaluated first, before the argument expression s = "two". Therefore, a reference to the string "one" is remembered as the target reference before the local variable s is changed to refer to the string "two". As a result, the startsWith method is invoked for target object "one" with argument "two", so the result of the invocation is false, as the string "one" does not start with "two". It follows that the test program does not print "oops".

bacar
  • 9,761
  • 11
  • 55
  • 75
1

First fooFunc, then bazFunc, and last barFunc

Here's some code that demonstrates it:

public class OrderJava {
  public static void main(String[] args) {
    fooFunc().barFunc(bazFunc());
  }

  public static Bar fooFunc() {
    System.out.println("I am fooFunc!");
    return new Bar();
  }

  public static class Bar {
    public void barFunc(Object o) {
      System.out.println("I am barFunc!");
    }
  }

  public static Object bazFunc() {
    System.out.println("I am bazFunc!");

    return null;
  }
}

The output of this code is:

I am fooFunc!
I am bazFunc!
I am barFunc!
durron597
  • 31,968
  • 17
  • 99
  • 158
  • 1
    Downvoting. The question is "is the order of execution guaranteed?" (implicitly: by a (language/JVM) specification), not "can you produce an example demonstrating what happens with one compiler and one JVM with one example". – bacar Dec 05 '12 at 14:14
  • You have really low standards for downvoting. It's useful to have a demonstration to a question like this; though I still think your answer should be the accepted one. – durron597 Dec 05 '12 at 14:17
  • On reflection, you're right, I think I'm being overzealous. The example I gave from the JLS is not a lot more useful than your answer, given how vague the JLS example is... undownvoted! – bacar Dec 05 '12 at 14:28
-1

fooFunc() will execute first, followed by bazFunc() and finally barFunc()

We can all agree that fooFunc() must execute before barFunc() has anything to operate on.

Given that bazFunc() will only be called when barFunc() needs it's parameters, it stands to reason that this would happen after fooFunc().

lynks
  • 5,599
  • 6
  • 23
  • 42
  • 4
    Can you back that up with a spec reference? – bacar Dec 05 '12 at 14:04
  • This makes sense, since the object accessor operator (`.`) evaluates from left-to-right, but I agree that it needs a source. – jonvuri Dec 05 '12 at 14:05
  • @bacar I believe it just follows logically, I will edit my answer. – lynks Dec 05 '12 at 14:05
  • the result of `bazFunc()` will be used as parameter for `barFunc()`, which is an instance method called on the result of `fooFunc()`. – jlordo Dec 05 '12 at 14:07
  • 1
    "Given that `bazFunc()` will only be called when `barFunc()` needs its parameters"... I do not think this a given. – jonvuri Dec 05 '12 at 14:08
  • @Kiyura if `barFunc()` didn't need parameters, the code wouldn't even compile. – jlordo Dec 05 '12 at 14:09
  • 1
    I think you're missing the crux of the question. Before the method invocation can take place, two pieces of information are needed: The value returned by `fooFunc()` (the object to find the method in), and the value returned by `barFunc()` (the value to pass to the method as its first parameter). They are otherwise unrelated except that they are both needed when this statement is executed. The question is which of them will be executed first, by the spec. Your answer is essentially "I think it's obvious that this one will come first." – jonvuri Dec 05 '12 at 14:14
  • @kiyura I don't see how it can happen in any other order, unless the compiler starts deciding to resolve statements that it hasn't reached yet. To me it *is* obvious, this is just how function calls work. I don't mean that to sound arrogant, I just can't see the ambiguity. – lynks Dec 05 '12 at 14:24
  • @lynks What does "it hasn't reached yet" mean? You already concede in your answer that the compiler doesn't just do a naive left-to-right, because you agree that `barFunc` must execute last despite being in the middle. – bacar Dec 05 '12 at 14:29
  • I must be missing something, to me this one's pretty clean cut. Resolution of parameters always happens immediately before a function call, semantically parameter resolution is *part* of the function call process in a high level language like this. The function definition is unknown until `fooFunc()` is called, so how could the function call start? – lynks Dec 05 '12 at 14:35
  • What you're missing is a link to the spec to back up "resolution of parameters happens immediately before a function call". The accepted answer provides it. Without a spec link, it's just your assertion (it could have been implemented the other way round, or with no guarantees, allowing the compiler to potentially optimise - the C++ standard leaves is unspecified, for instance...) – bacar Dec 05 '12 at 15:00