Order of execution of methods describing an instance and an argument in Java?
Asked Answered
C

4

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?

Commencement answered 5/12, 2012 at 14:1 Comment(5)
1st. fooFunc(), than bazFunc(), at last barFunc()Lotta
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.Frontiersman
@Kiyura what are you saying? The order of execution is definitely guaranteed here.Lotta
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.Commencement
I would add that compiler/runtime can reorder the executions, as long as the effect is the same.Mary
D
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.

Deceptive answered 5/12, 2012 at 14:12 Comment(1)
Just to augment this answer - Part 2 of Section 15.12.4.1. Compute Target Reference (If Necessary) 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.)Frontiersman
C
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".

Commencement answered 5/12, 2012 at 14:6 Comment(0)
W
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!
Watchtower answered 5/12, 2012 at 14:7 Comment(3)
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".Commencement
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.Watchtower
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!Commencement
S
-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().

Significant answered 5/12, 2012 at 14:3 Comment(11)
Can you back that up with a spec reference?Commencement
This makes sense, since the object accessor operator (.) evaluates from left-to-right, but I agree that it needs a source.Frontiersman
@Commencement I believe it just follows logically, I will edit my answer.Significant
the result of bazFunc() will be used as parameter for barFunc(), which is an instance method called on the result of fooFunc().Lotta
"Given that bazFunc() will only be called when barFunc() needs its parameters"... I do not think this a given.Frontiersman
@Kiyura if barFunc() didn't need parameters, the code wouldn't even compile.Lotta
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."Frontiersman
@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.Significant
@Significant 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.Commencement
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?Significant
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...)Commencement

© 2022 - 2024 — McMap. All rights reserved.