Given is the following Java code example:
builder.something()
.somethingElse()
.somethingMore(builder.getSomething());
Is it guaranteed by the Java Language Specification that getSomething() is invoked after the somethingElse() method or is a Java implementation allowed to reorder the execution?
The JLS, Section 15.12.4, guarantees that the target reference is computed before arguments are evaluated.
At run time, method invocation requires five steps. First, a target reference may be computed. Second, the argument expressions are evaluated. ...
The somethingElse method must be evaluated first, to compute the target reference for the somethingMore method. Then builder.getSomething() is evaluated to supply a value for the parameter to somethingMore. Then somethingMore can be executed.
Because of this rule, JVMs are not allowed to reorder the execution.
Related
As far as I know, when you define a method in a function, an object is instantiated:
myList.stream().map(x->x.getName().replaceAll('a','b')).toList();
Or the equivalent
Function<MyObject,String> myFunc = x -> {return x.getName().replaceAll('a','b');}
myList.stream().map(myFunc).toList();
x->x.getName().replaceAll('a','b') is created as a functional interface object (and requires memory allocation, a new somewhere/somehow, right?).
However, if I pass an already existing method as a parameter, is anything created?
class A{
public list<String> transform(List<String> input){
return input.stream().filter(this::myFilter).filter(A::staticFilter).toList();
}
public boolean myFilter(String s){ // Whatever }
public static boolean staticFilter(String s) { // whatever }
}
What happens here:
Is myFilter "wrapped" in a functional interface? (is it the same for a static method reference?)
Is there something specific that happens at bytecode level which is not "clear" on language level (like method pointer or something?).
From JavaDoc Api
Note that instances of functional interfaces can be created with
lambda expressions, method references, or constructor references.
As to if the lambda expression will create an instance in heap or not, you can follow this thread where the top comment from #Brian Goetz might be helpful.
About lambda expressions:
Also as indicated here in Java Specifications for Run-Time Evaluation of Lambda Expressions
These rules are meant to offer flexibility to implementations of the
Java programming language, in that:
A new object need not be allocated on every evaluation.
Objects produced by different lambda expressions need not belong to
different classes (if the bodies are identical, for example).
Every object produced by evaluation need not belong to the same class
(captured local variables might be inlined, for example).
If an "existing instance" is available, it need not have been created
at a previous lambda evaluation (it might have been allocated during
the enclosing class's initialization, for example).
So to your question:
x->x.getName().replaceAll('a','b') is created as a functional
interface object (and requires memory allocation, a new
somewhere/somehow, right?).
The answer is some times yes, some times no. Not always the same case.
About method reference expressions:
Evaluation of a method reference expression produces an instance of a
functional interface type (§9.8). Method reference evaluation does not
cause the execution of the corresponding method; instead, this may
occur at a later time when an appropriate method of the functional
interface is invoked.
Based on what is written here for Run-Time Evaluation of Method References
The timing of method reference expression evaluation is more complex
than that of lambda expressions (§15.27.4). When a method reference
expression has an expression (rather than a type) preceding the ::
separator, that subexpression is evaluated immediately. The result of
evaluation is stored until the method of the corresponding functional
interface type is invoked; at that point, the result is used as the
target reference for the invocation. This means the expression
preceding the :: separator is evaluated only when the program
encounters the method reference expression, and is not re-evaluated on
subsequent invocations on the functional interface type.
I would assume that a functional interface type is created but not each time with each invocation. It should as well be cached and optimized for the less amount of evaluations.
Well, the compiler has a lot of leeway in how it actually implements the code you write, but generally .map() takes a Function Object so whatever expression you put in the parentheses will produce an object.
That does not mean, however, that a new Object is created every time. In your lambda example, the lambda function doesn't reference anything defined in an enclosing method scope, so a single Function object can be created and reused for all calls.
Similarly, the A::staticFilter reference only needs to produce one Function.
The object created by this::myFilter, however, needs to have a reference to this (unless the compiler can determine that it doesn't!), and so you will certainly get a new Function created inside each call to transform.
Dealing with another SO question, I was wondering if the code below has an undefined behavior:
if (str.equals(str = getAnotherString())) {
// [...]
}
I tend to think the str reference from which the equals() call is made is evaluated before the further str assignment passed as argument. Is there a source about it?
This is clearly specified in the JLS Section 15.12.4:
At run time, method invocation requires five steps. First, a target reference may be computed. Second, the argument expressions are evaluated. [...]
What's a "target reference" you ask? This is specified in the next subsection:
15.12.4.1. Compute Target Reference (If Necessary)
...
If form is ExpressionName . [TypeArguments] Identifier, then:
If the invocation mode is static, then there is no target reference. The ExpressionName is evaluated, but the result is then discarded.
Otherwise, the target reference is the value denoted by ExpressionName.
So the "target reference" is the str bit in str.equals - the expression on which you are calling the method.
As the first quote says, the target reference is evaluated first, then the arguments. Therefore, str.equals(str = getAnotherString()) only evaluates to true if getAnotherString returns a string that has the same characters as str before the assignment expression.
So yeah, the thing that you tend to think is correct. But this is not "undefined behaviour".
I am still new to Scala.
I found this code inside Spray framework.
I am trying to understand what the method signature means:
/**
* Completes the request using the given arguments.
*/
def complete: (⇒ ToResponseMarshallable) ⇒ StandardRoute = marshallable ⇒ new StandardRoute {
def apply(ctx: RequestContext): Unit = ctx.complete(marshallable)
}
What does the => operator do here? I thought it was used for creating a closure?
What is the assignment to marshallable being done here? why is it done outside the brackets?
A java version of this code would be nice to see.
So.
The first thing to notice is that complete is declared with a def, so it is a method, but the parentheses that look like they might be method arguments come after the colon :.
So they are not in fact method arguments. complete is a no-argument method!
Then what's up with the parens after the colon?
(⇒ ToResponseMarshallable) ⇒ StandardRoute is the return type of the no-arg method complete. The function complete returns a function that accepts an expression of type ToResponseMarshallable and returns a StandardRoute.
OK. But then what's up with the arrow before ToResponseMarshallable in the function signature (⇒ ToResponseMarshallable) ⇒ StandardRoute?
In a function signature, an ⇒ prior to the type name signifies a "call-by-name" argument. Following java, Scala by default evaluates all expressions in an argument list, and then evaluates the method body, substituting the evaluated values for the variable. But Scala also supports call-by-name semantics, in which an expression is substituted unevaluated into a function, and re-executed every time that it is named. complete returns a function whose single argument has call-by-name semantics.
Following the equals sign is just the implementation of this method. The expression beginning with marshallable ⇒ is an anonymous function, or function literal, or lambda (all names for basically the same thing). marshallable ⇒ "hello" would be a function that accepts (by name) a ToResponseMarshallable and returns the String "hello". But we need a method that accepts a ToResponseMarshallable (by name) and retuns a StandardRoute. So we have marshallable ⇒<expression that evaluates to a StandardRoute>
That <expression that evaluates to a StandardRoute> is just an anonymous inner class, an implementation of StandardRoute that overrides its apply method.
And we're done! We (hopefully) understand all the pieces, and what this declaration means.
Inspired by another question, I started wondering about the well-definedness of the following Java code:
public class Test {
List<Object> foo;
Object bar() {
foo = new ArrayList<Object>():
return(/* Anything */);
}
void frob() {
foo.add(bar());
}
}
In this case, does the Java specification specify a strict order of evaluation for the dot operator in frob? Is left-to-right evaluation guaranteed such that the add method is always executed on the list that was there before bar replaces the field with a new list, or can there legally be compilers that let bar execute before the foo field is fetched in frob, thus executing the add method on the new list?
I suspect that left-to-right evaluation is guaranteed, but is there wording in the specification to this effect?
Yes, this is part of Run-time Evaluation of Method Invocation - Compute Target Reference
If the form is Primary . [TypeArguments] Identifier involved, then:
If the invocation mode is static, then there is no target reference. The Primary expression is evaluated, but the result is then
discarded.
Otherwise, the Primary expression is evaluated and the result is used as the target reference.
Then comes the evaluation of method arguments.
I used to think that, intuitively speaking, a constructor in Java is the thing that makes an object, and that nothing can touch that object until its constructor returns. However, I have been proven wrong about this over and over again:
uninitialized objects can be leaked by sharing this
uninitialized objects can be leaked by a subclass accessing it from the finalizer
uninitialized objects can be leaked to another thread before they're fully constructed
All of these facts violate my intuition of what I thought a constructor is.
I can no longer with confidence say what a constructor actually does in Java, or what it's meant to be used for. If I'm making a simple DTO with all final fields, then I can understand what the use of the constructor is, because this is exactly the same as a struct in C except it can't be modified. Other than that, I have no clue what constructors can be reliably used for in Java. Are they just a convention/syntactic sugar? (i.e If there were only factories that initialize objects for you, you would only have X x = new X(), then modify each field in x to make them have non default values - given the 3 facts above, this would be almost equivalent to how Java actually is)
I can name two properties that are actually guaranteed by constructors: If I do X x = new X(), then I know that x is an instance of X but not a subclass of X, and its final fields are fully initialized. You might be tempted to say that you know that constructor of X finished and you have a valid object, but this is untrue if you pass X to another thread - the other thread may see the uninitialized version (i.e what you just said is no different than the guarantees of calling a factory). What other properties do constructors actually guarantee?
All of these facts violate my intuition of what I thought a constructor is.
They shouldn't. A constructor does exactly what you think it does.
1: uninitialized objects can be leaked by sharing this
3: uninitialized objects can be leaked to another thread before they're fully constructed
The problem with the leaking of this, starting threads in the constructor, and storing a newly constructed object where multiple threads access it without synchronization are all problems around the reordering of the initialization of non-final (and non-volatile) fields. But the initialization code is still done by the constructor. The thread that constructed the object sees the object fully. This is about when those changes are visible in other threads which is not guaranteed by the language definition.
You might be tempted to say that you know that constructor of X finished and you have a valid object, but this is untrue if you pass X to another thread - the other thread may see the uninitialized version (i.e what you just said is no different than the guarantees of calling a factory).
This is correct. It is also correct that if you have an unsynchronized object and you mutate it in one thread, other threads may or may not see the mutation. That's the nature of threaded programming. Even constructors are not safe from the need to synchronize objects properly.
2: uninitialized objects can be leaked by a subclass accessing it from the finalizer
This document is talking about finalizers and improperly being able to access an object after it has been garbage collected. By hacking subclasses and finalizers you can generate an object that is not properly constructed but it is a major hack to do so. For me this does not somehow challenge what a constructor does. Instead it demonstrates the complexity of the modern, mature, JVM. The document also shows how you can write your code to work around this hack.
What properties are guaranteed by constructors in Java?
According to the definition, a constructor:
Allocates space for the object.
Sets all the instance variables in the object to their default values. This includes the instance variables in the object's superclasses.
Assigns the parameter variables for the object.
Processes any explicit or implicit constructor invocation (a call to this() or super() in the constructor).
Initializes variables in the class.
Executes the rest of the constructor.
In terms of your 3 issues, #1 and #3 are, again, about when the initialization of non-final and non-volatile fields are seen by threads other than the one that constructed the object. This visibility without synchronization is not guaranteed.
The #2 issue shows a mechanism where if an exception is thrown while executing the constructor, you can override the finalize method to obtain and improperly constructed object. Constructor points 1-5 have occurred. With the hack you can bypass a portion of 6. I guess it is in the eye of the beholder if this challenges the identity of the constructor.
From the JLS section 12.5:
12.5. Creation of New Class Instances
Just before a reference to the newly created object is returned as the
result, the indicated constructor is processed to initialize the new
object using the following procedure:
Assign the arguments for the constructor to newly created parameter variables for this constructor invocation.
If this constructor begins with an explicit constructor invocation (§8.8.7.1) of another constructor in the same class (using this), then
evaluate the arguments and process that constructor invocation
recursively using these same five steps. If that constructor
invocation completes abruptly, then this procedure completes abruptly
for the same reason; otherwise, continue with step 5.
This constructor does not begin with an explicit constructor invocation of another constructor in the same class (using this). If
this constructor is for a class other than Object, then this
constructor will begin with an explicit or implicit invocation of a
superclass constructor (using super). Evaluate the arguments and
process that superclass constructor invocation recursively using these
same five steps. If that constructor invocation completes abruptly,
then this procedure completes abruptly for the same reason. Otherwise,
continue with step 4.
Execute the instance initializers and instance variable initializers for this class, assigning the values of instance variable
initializers to the corresponding instance variables, in the
left-to-right order in which they appear textually in the source code
for the class. If execution of any of these initializers results in an
exception, then no further initializers are processed and this
procedure completes abruptly with that same exception. Otherwise,
continue with step 5.
Execute the rest of the body of this constructor. If that execution completes abruptly, then this procedure completes abruptly
for the same reason. Otherwise, this procedure completes normally.
**
Unlike C++, the Java programming language does not specify altered rules for method >dispatch during the creation of a new class instance. If methods are invoked that are >overridden in subclasses in the object being initialized, then these overriding methods >are used, even before the new object is completely initialized.
And from JLS 16.9:
Note that there are no rules that would allow us to conclude that V is
definitely unassigned before an instance variable initializer. We can
informally conclude that V is not definitely unassigned before any
instance variable initializer of C, but there is no need for such a
rule to be stated explicitly.
Happens before 17.4.5:
Threading 17.5.2:
A read of a final field of an object within the thread that constructs
that object is ordered with respect to the initialization of that
field within the constructor by the usual happens-before rules. If the
read occurs after the field is set in the constructor, it sees the
value the final field is assigned, otherwise it sees the default
value.
A class contains constructors that are invoked to create objects from the class blueprint.
This is what Oracle says about constructors.
Now to your point.
intuitively speaking, a constructor in Java is the thing that makes an object, and that nothing can touch that object until its constructor returns.
So according to the official documentation, your assumption is not right. And the point 1 and 2 are the abuse of the rules and behaviors of Java, unless you consciously want to leak your objects! As also being irrelevant to Constructor, I will skip discussing these points.
Now if we talk about your 3rd point, in multi-threaded environment there is nothing that can guarantee you about the consistency of your code, unless "properly synchronized blocks" or "the atomic instructions". As object creation is not a synchronized nor an atomic instruction, there is no guarantee of being consistent! There is nothing the Constructor can do with it. In other words its not the responsibility of the Constructor to make your object creation atomic.
Now, the answer to your question, "What other properties do constructors actually guarantee?" is somewhat easy. Constructors are merely nothing but special type of methods, that are invoked during object creation from the blue print of the class. So it can guarantee nothing, unless you give it a chance to be executed consistently like any other methods. It after being consistently executed it can guarantee you that, your object is created and initialized as you wanted and instructed in it.
constructors is java are just used to initialize the state of the object created..nothing more.