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.
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.
As I understand, in languages such as Haskell, and also as part of the lambda calculus, each lambda expression has its own scope, so if I have nested lambda expressions such as: \x -> (\x -> x) then the first \x parameter is different to the second \x.
In Java if you do this you get a compilation error, just like if you use x again as the parameter name or a local variable name within the lambda if it has already been used inside the enclosing scope, e.g. as a method parameter.
Does anybody know why Java implemented lambda expressions this way - why not have them introduce a new level of scope and behave like an anonymous class would? I'm assuming it's because of some limitation or optimisation, or possibly because lambdas had to be hacked into the existing language?
This is the same behaviour as for other code blocks in Java.
This gives a compilation error
int a;
{
int a;
}
while this does not
{
int a;
}
{
int a;
}
You can read about this topic in section 6.4 of the JLS, together with some reasoning.
A lambda block is a new block, aka scope, but it does not establish a new context/level, like an anonymous class implementation does.
From Java Language Specification 15.27.2 Lambda Body:
Unlike code appearing in anonymous class declarations, the meaning of names and the this and super keywords appearing in a lambda body, along with the accessibility of referenced declarations, are the same as in the surrounding context (except that lambda parameters introduce new names).
And from JLS 6.4 Shadowing and Obscuring:
These rules allow redeclaration of a variable or local class in nested class declarations (local classes (§14.3) and anonymous classes (§15.9)) that occur in the scope of the variable or local class. Thus, the declaration of a formal parameter, local variable, or local class may be shadowed in a class declaration nested within a method, constructor, or lambda expression; and the declaration of an exception parameter may be shadowed inside a class declaration nested within the Block of the catch clause.
There are two design alternatives for handling name clashes created by lambda parameters and other variables declared in lambda expressions. One is to mimic class declarations: like local classes, lambda expressions introduce a new "level" for names, and all variable names outside the expression can be redeclared. Another is a "local" strategy: like catch clauses, for loops, and blocks, lambda expressions operate at the same "level" as the enclosing context, and local variables outside the expression cannot be shadowed. The above rules use the local strategy; there is no special dispensation that allows a variable declared in a lambda expression to shadow a variable declared in an enclosing method.
Example:
class Test {
private int f;
public void test() {
int a;
a = this.f; // VALID
{
int a; // ERROR: Duplicate local variable a
a = this.f; // VALID
}
Runnable r1 = new Runnable() {
#Override
public void run() {
int a; // VALID (new context)
a = this.f; // ERROR: f cannot be resolved or is not a field
// (this refers to the instance of Runnable)
a = Test.this.f; // VALID
}
};
Runnable r2 = () -> {
int a; // ERROR: Lambda expression's local variable a cannot redeclare another local variable defined in an enclosing scope.
a = this.f; // VALID
};
}
}
Lambdas in Java do introduce a new scope - any variable declared in a lambda is only accessible within the lambda.
What you really ask about is shadowing - changing binding of a variable already bound in some outer scope.
It is logical to allow some level of shadowing: you want to be able to shadow global names by local names, because otherwise you can break local code just by adding a new name to some global namespace. A lot of langues, for sake of simplicity, simply extend this rule down to local names.
On the other hand, rebinding local names is a code smell and can be a source of subtle mistakes, while - at the same time - not offering any technical advantage. Since you mentioned Haskell, you can look at this discussion on Lambda the Ultimate.
This is why Java disallows shadowing of local variables (like many other potentially dangerous things), but allows shadowing attributes by local variables (so that adding attributes will never break a method that already used the name).
So, the designers of Java 8 had to answer a question if lambdas should behave more like code blocks (no shadowing) or like inner classes (shadowing) and made a conscious decision to treat them like the former.
While the other answers make it seem like this was a clear-cut decision by the language designers, there is actually a JEP that proposes to introduce shadowing for lambda parameters (emphasis mine):
Lambda parameters are not allowed to shadow variables in the enclosing
scopes. [...] It would be desirable to lift this restriction, and
allow lambda parameters (and locals declared with a lambda) to shadow
variables defined in enclosing scopes.
The proposal is relatively old and has obviously not found its way into the JDK yet. But since it also includes a better treatment of the underscore (which was deprecated as an identifier in Java 8 to pave the way for this treatment), I could image that the proposal as a whole is not completely off the table.
While I was reading the javadoc about ForkJoinTask I came across the following statement:
This method may be invoked only from within ForkJoinPool computations
(as may be determined using method inForkJoinPool()). Attempts to
invoke in other contexts result in exceptions or errors, possibly
including ClassCastException.
What's not clear to me is what ForkJoinContext means here. I know what static context means, for example. It clearly defines in the JLS 8.1.3 as follows (Emphasize's mine):
A statement or expression occurs in a static context if and only if
the innermost method, constructor, instance initializer, static
initializer, field initializer, or explicit constructor invocation
statement enclosing the statement or expression is a static method, a
static initializer, the variable initializer of a static variable, or
an explicit constructor invocation statement (§8.8.7).
The context being discussed here is not static/non-static context.
It means that the method must be called from a thread which belongs to the ForkJoinPool.
So it must be called from a recursive task. Calling from anywhere else might cause exceptions/errors.
I have the following piece of code-
{s = "Hello";}
String s;
This compiles fine, implying that the variable definitions are executed before the instance blocks.
However, if I use the following code instead, it does not compile ("error: illegal forward reference").
{s = "Hello"; String ss = s;}
String s;
So it is not possible to use the value of 's' on the right-hand side of a statement in an instance block that comes BEFORE the variable
definition. Is there a sane explanation of what is happening behind the scenes, or is this simply an idiosyncratic feature of Java?
P.S. I have seen a similar question asked before, the only explanation given there is that it is a feature of Java.
I am writing this to ask the community if that is indeed the final word on this question.
JLS §8.3.3 ("Forward References During Field Initialization") sheds some light here:
Use of instance variables whose declarations appear textually after the use is sometimes restricted, even though these instance variables are in scope. Specifically, it is a compile-time error if all of the following are true:
The declaration of an instance variable in a class or interface C appears textually after a use of the instance variable;
The use is a simple name in either an instance variable initializer of C or an instance initializer of C;
The use is not on the left hand side of an assignment;
C is the innermost class or interface enclosing the use.
The first bullet would apply to your example.
As for the "why" part, "why" is usually a tricky question with language design, but in this case they helpfully added this note further down:
The restrictions above are designed to catch, at compile time, circular or otherwise malformed initializations.
In second case you will get compilation error IllegalForwardReference due to the fact that usage of the variable s is not on the left hand side of an assignment and JLS explicitly states it as one of the reason to get IllegalForwardReference error
I just can tell you this: The compiler moves all the initialization code to the end of the constructors' body (repeating code for every constructor). Decompiling an example would show it off.
So, you must realise that, in this way, the declaration order of some variable matters when evaluating it as a right-hand side, even if it doesn't matter when evaluating it as a left-hand side.
One way to get rid off these incoherences is to pre-pend the scope "this" to every instance variable.
In the Java DOM/AST (http://help.eclipse.org/indigo/topic/org.eclipse.jdt.doc.isv/reference/api/org/eclipse/jdt/core/dom/package-tree.html) why does an Initializer contain a Block and why is a MethodInvocation an Expression and not a Statement?
I mean, given the code
int a = Integer.parseInt("1");
the ASTView plugin shows me only INITIALIZER > MethodInvocation
Can there ever be an Initializer that really has a Block element?
Moreover, if I have a method like this
public void thisMethod(){
System.out.println();
}
MethodInvocation is wrapped into an ExpressionStatement. But why isn't MethodInvocation a Statement? Just a simple System.out.println() is a valid "Statement". An Expression in the sense of the Java DOM/AST lacks the ability to stand for itself.
Maybe I just didn't the get the whole idea of the separation between Expression and Statement.
The AST tree is designed to reflect the syntax rules of the programming language.
Syntactically, an Initializer consists of a block with an optional static modifier before it. So it’s the most natural implementation having an Initializer class consisting of a Block and modifiers (inherited from BodyDeclaration). So I don’t understand why you question it.
Example of initializers:
class Foo {
static {
System.out.println("static initializer");
System.out.println("class Foo now initialized");
}
{
System.out.println("instance initializer");
System.out.println("an instance of Foo has been created");
}
}
Expressions and statements are two different syntactic constructs. There are places where only either an expression or a statement is allowed. But there are constructs like method invocations which are Expression Statements which means the can fulfill both roles, Expression and Statement. They can be invoked stand-alone for their side-effects but also at places where a value is required.
But since Java does not allow multiple inheritance you cannot create an AST class ExpressionStatement inheriting from both Expression and Statement. So you need a solution like in the Eclipse AST where ExpressionStatement inherits from one and wraps the other. The decision which one to inherit and which one to wrap is easy: you can create a Statement implementation (subclass) which drops the result of the Expression it has wrapped but you cannot create an Expression implementation which provides a result for a Statement that provides no result through its interface. An alternative to such an implementation would be the use of interfaces.