what does this scala code do? - java

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.

Related

Is an object created when you pass a method reference in a method

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.

Places where an expression can occur as per the JLS?

Consider the Article §15.1 regarding places where the expression can occur:
An expression occurs in either:
• The declaration of some (class or interface) type that is being declared: in a
field initializer, in a static initializer, in an instance initializer, in a constructor
declaration, in a method declaration, or in an annotation.
• An annotation on a package declaration or on a top level type declaration.
I don't think this is exhaustive list of all occurrence places for expression - as eg:
int a=23; //declaration of a local type
a=33; //this is re-initialization of the type
//or like a simple method invocation from inside a method like
foo();
The places where we are trying to re-initialize the expression are not highlighted by this clause.
also the simple method invocation is not being highlighted in the above clause - even though it is a formal expression.
Is the clause above correct - or is just a casual statement in the JLS?
That clause is actually true, though it is not stated in a precise way.
For example:
a=33;
The a=33 is an expression, and when followed by a ; it is also an expression statement. An expression statement is only allowed where other statements are allowed; i.e. within a method or constructor declaration (in the body), or in an instance or static initializer (block).
Note that in the JLS, a method's body is part of the method's declaration. That is why we can say that statements are within a method declaration.
foo();
The foo() call is an expression, and when followed by a ; it is also an expression statement; see above.
It is a matter of understanding what is meant by "in" in this context. It means "inside of" rather than "directly inside of".
The imprecision arises when you consider that an expression statement that is inside of a method declaration that is inside of a class is ... also indirectly inside the class.
You could argue that the clause descriptive rather than normative since they don't specify precisely what "in" means in this context. But even so, the description is correct if you interpret it as above.
Your int a=23; "example" is not an expression, so it is not apropos to the point you are trying to make. It could be a statement, or it could be a (package private) field declaration that is "in" a class or interface declaration.

Evaluation order between a method call and arguments in Java

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".

overloading using an argument that was returned from a method with generic return type [duplicate]

The sample code is :
public class OverloadingTest {
public static void test(Object obj){
System.out.println("Object called");
}
public static void test(String obj){
System.out.println("String called");
}
public static void main(String[] args){
test(null);
System.out.println("10%2==0 is "+(10%2==0));
test((10%2==0)?null:new Object());
test((10%2==0)?null:null);
}
And the output is :
String called
10%2==0 is true
Object called
String called
The first call to test(null) invokes the method with String argument , which is understandable according to The Java Language Specification .
1) Can anyone explain me on what basis test() is invoked in preceding calls ?
2) Again when we put , say a if condition :
if(10%2==0){
test(null);
}
else
{
test(new Object());
}
It always invokes the method with String argument .
Will the compiler compute the expression (10%2) while compiling ? I want to know whether expressions are computed at compile time or run time . Thanks.
Java uses early binding. The most specific method is chosen at compile time. The most specific method is chosen by number of parameters and type of parameters. Number of parameters is not relevant in this case. This leaves us with the type of parameters.
What type do the parameters have? Both parameters are expressions, using the ternary conditional operator. The question reduces to: What type does the conditional ternary operator return? The type is computed at compile time.
Given are the two expressions:
(10%2==0)? null : new Object(); // A
(10%2==0)? null : null; // B
The rules of type evaluation are listed here. In B it is easy, both terms are exactly the same: null will be returned (whatever type that may be) (JLS: "If the second and third operands have the same type (which may be the null type), then that is the type of the conditional expression."). In A the second term is from a specific class. As this is more specific and null can be substituted for an object of class Object the type of the whole expression is Object (JLS: "If one of the second and third operands is of the null type and the type of the other is a reference type, then the type of the conditional expression is that reference type.").
After the type evaluation of the expressions the method selection is as expected.
The example with if you give is different: You call the methods with objects of two different types. The ternary conditional operator always is evaluated to one type at compile time that fits both terms.
JLS 15.25:
The type of a conditional expression is determined as follows:
[...]
If one of the second and third operands is of the null type and the type of the other
is a reference type, then the type of the conditional expression is that reference
type.
[...]
So the type of
10 % 2 == 0 ? null : new Object();
is Object.
test((10%2==0)?null:new Object());
Is the same as:
Object o;
if(10%2==0)
o=null;
else
o=new Object();
test(o);
Since type of o is Object (just like the type of (10%2==0)?null:new Object()) test(Object) will be always called. The value of o doesn't matter.
Your answer is : Runtime because in runtime specify parameter is instance of String or not so in compile-time can't find this.
This is the really nice question.
Let me try to clarify your code that you have written above.
In your first method call
test(null);
In this the null will be converted into string type so calling the test(String obj), as per JLS you are convinced with the call.
In the second method call
test((10%2==0)?null:new Object());
Which is going to return the boolean "true" value. So first boolean "true" value is going to auto cast into Boolean Wrapper class object. Boolean wrapper Object is finding the best match with your new Object() option in the ternary operator. And the method calls with Object as a parameter so it calls the following method
public static void test(Object obj)
For the experiment sake you can try the following combinations then you will get better clarity.
test((10 % 2 == 0) ? new Object() : "stringObj" );
test((10 % 2 == 0) ? new Object() : null );
test((10 % 2 == 0) ? "stringObj" : null );
Finally in the last when you are calling with the following code.
test((10%2==0)?null:null);
This time again it returns as boolean "true" value, and it will again follow the same casts as explained above. But this time there is no new Object() parameter is there in your ternary operator. So it will be auto type cast into null Object. Again it follows same method call as the your first method call.
In the last when you asked for code if you put in if .. else statement. Then also the compiler doing the fair decision with the code.
if(10%2==0) {
test(null);
}
Here all the time your if condition is true and calling this code test(null). Therefore all the time it call the firsttest(String obj) method with String as parameter as explained above.
I think your problem is that you are making the wrong assumption, your expressions:
test((10%2==0)?null:new Object());
and
test((10%2==0)?null:null;
Will always call test(null), and that's why they will go through test (Object).
as #Banthar mentionend the ?: operator assigns a value to a variable first then evaluates the condition.
On the other hand, the if condition you mentioned always returns true, so the compiler will replace the whole if-else block with only the body of the if.
1) the test() method is determined by the type of the parameter at the compilation time :
test((Object) null);
test((Object)"String");
output :
Object called
Object called
2) The compiler is even smarter, the compiled code is equivalent to just :
test(null);
you can check the bytecode with javap -c:
0: aconst_null
1: invokestatic #6 // Method test:(Ljava/lang/String;)V
4: return
This is what Java Language Specifications say about the problem.
If more than one method declaration is both accessible and applicable
to a method invocation, it is necessary to choose one to provide the
descriptor for the run-time method dispatch. The Java programming
language uses the rule that the most specific method is chosen.
This is test(String) method in your case.
And because of that if you add...
public static void test(Integer obj){
System.out.println("Ingeter called");
}
it will show compilation error -The method test(String) is ambiguous for the type OverloadingTest.
Just like JLS says:
It is possible that no method is the most specific, because there are
two or more maximally specific methods. In this case:
If all the maximally specific methods have the same signature, then:
If one of the maximally specific methods is not declared abstract, it
is the most specific method. Otherwise, all the maximally specific
methods are necessarily declared abstract. The most specific method is
chosen arbitrarily among the maximally specific methods. However, the
most specific method is considered to throw a checked exception if and
only if that exception is declared in the throws clauses of each of
the maximally specific methods. Otherwise, we say that the method
invocation is ambiguous, and a compile-time error occurs.

What actually happens in the compiler in this case

I have a small question, given the following snippet:
StringBuilder stringBuild = new StringBuilder(3);
stringBuild.append("hello");
System.out.println(stringBuild+2); // if I omit the (+2) bit hence only stringBUild it works
Does it call automatically toString() on object only in some circumstances? (circumstances: either no operation at all or a previous string contatanation)
The compiler never calls toString() on a method argument implicitly.
What you are probably thinking of, is that there is an overload of System.out.println which takes an Object (rather than a String) - this is the method that the compiler would link to. And this particular implementation of the method calls toString on the Object passed in (at runtime). That's just code though, it's nothing to do with compiler behaviour.
So passing in an Object to System.out.println "works". Passing in stringBuild+2 simply doesn't compile - there's no + operator on StringBuilder which takes an int. (And you can't create one yourself as Java doesn't allow for operator overloading.)
As ADTC and tom point out, there is implicit String conversion with the second argument to string concatenation (the + operator for strings). So while stringBuild doesn't have a + operator, stringBuild.toString() would, and you could call stringBuild.toString()+2.

Categories