<div dir="ltr"><div>I'm starting to have a weird fondness for obscure JLS corners like this :)</div><div><br></div><div>Some thoughts...</div><div><br></div><div>From a purely practical point of view, the "static context" concept seems to exist to prevent these two bad things:<br></div><div><ol><li>Accessing the 'this' object (via this, super, or any implicit means) when there is no such object available</li><li>Accessing the 'this' object (via this, super, or any implicit means) when that object is uninitialized</li></ol></div><div>(Are there others?) By "bad things" I mean problems with language semantics, not problems because the compiler happens to be implemented a certain way.<br></div><div><br></div><div>The example <span class="gmail-im"><span style="font-family:monospace">super(new Local().aString())</span> </span>can never be allowed, because of #2 above. But note you can <i>define</i> Local prior to <span style="font-family:monospace">super()</span> ... you just can't instantiate it. <br></div><div><br></div><div>In other words the type itself is not a problem. There's no mention of types at all in the above two reasons.<br></div><div><br></div><div>So one thought experiment is: What would happen if we eliminated all restrictions on generic type parameters in static contexts? What would actually go wrong?<br></div><div><br></div><div>Put another way, a static method is just an instance method without a 'this' instance. So neither issue #1 or #2 is possible. So, no problem, right?<br></div><div dir="ltr"><br></div><div>You might be able to write code that looks silly, but would it actually be nonsensical?<br></div><div dir="ltr"><br></div><div><span style="font-family:monospace">    public class Foo<T extends Number> {</span></div><div><span style="font-family:monospace">        public static toFloat(T value) {</span></div><div><span style="font-family:monospace">            return value.floatValue();   // why not?<br></span></div><div><span style="font-family:monospace">        }<br></span></div><div><span style="font-family:monospace">    }<br></span></div><div dir="ltr"><br></div><div>I'm sure I'm missing something but what?</div><div><br></div><div>-Archie<br></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Wed, Feb 1, 2023 at 7:05 PM Alex Buckley <<a href="mailto:alex.buckley@oracle.com">alex.buckley@oracle.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">On 2/1/2023 4:31 PM, Maurizio Cimadamore wrote:> And, if we add <br>
statements before |super| it gets even worse, because now<br>
> we can have types that are non-static, but that it’s not clear as to why <br>
> such types couldn’t be referred to:<br>
> <br>
> |class Foo { Foo() { class Local { String aString() { ... } } super(new <br>
> Local().aString()); // is this legal? } } |<br>
<br>
To answer the question: the argument to `super(..)` is presently not <br>
legal because the `new Local()` part is presently not legal. (15.9.2: <br>
"If <<Local>> is an inner local class, then ... if the class instance <br>
creation expression occurs in a static context, then a compile-time <br>
error occurs.")<br>
<br>
But you are saying this is "static context overreach", and that perhaps <br>
`new Local()` should be allowed there. Such an expression needs to use <br>
`this` as the immediately enclosing instance of the Local object, and <br>
that's fine as long as no-one can access the immediately enclosing <br>
instance ... but now we invoke a method on the Local object and ????<br>
<br>
> Now that we’re planning to do more work in this area [1], it would be <br>
> IMHO a good time to see if the use of “static context” in 8.8.7.1 is <br>
> really what we want.<br>
<br>
I don't disagree.<br>
<br>
Alex<br>
<br>
> Maurizio<br>
> <br>
> [1] - <a href="https://bugs.openjdk.org/browse/JDK-8300786" rel="noreferrer" target="_blank">https://bugs.openjdk.org/browse/JDK-8300786</a><br>
> <br>
>><br>
>> Alex<br>
>><br>
>> On 2/1/2023 3:43 PM, Maurizio Cimadamore wrote:<br>
>>> While I agree that what javac does is against the JLS, is this a <br>
>>> javac or a spec bug?<br>
>>><br>
>>> I mean, consider this hierarchy:<br>
>>><br>
>>> |class Sup<X> { Sup(X x) { ... } } class Sub<Y> extends Sup<Y> { <br>
>>> Sub(Y y) { super(y); } } |<br>
>>><br>
>>> What the rules are saying is that “y” in the Sub super call should be <br>
>>> evaluated in a static context. But that doesn’t make any sense - <br>
>>> because Y is not even a valid type in such a static context.<br>
>>><br>
>>> And yet - this is a valid program. So, if typechecking “y” is <br>
>>> correct, then, surely, typechecking “(Y)y” should also be correct? <br>
>>> E.g. it seems to me that the use of “static context” here is an <br>
>>> “approximation” for the behavior we really want (e.g. no access to <br>
>>> instance fields, whether directly or indirectly).<br>
>>><br>
>>> Maurizio<br>
>>><br>
>>> On 01/02/2023 22:39, Alex Buckley wrote:<br>
>>><br>
>>>> Your reading of the JLS is correct. The cast expression `(T)obj` <br>
>>>> occurs in a static context, so the use of T should be disallowed, <br>
>>>> and javac should reject the program.<br>
>>>><br>
>>>> These rules in 8.8.7.1 and 8.1.3 are longstanding, and have not <br>
>>>> changed recently, so I'm surprised that javac lets the program <br>
>>>> through. That said, JLS16 saw a reworking of 8.1.3 (driven by <br>
>>>> <a href="https://openjdk.org/jeps/395#Static-members-of-inner-classes" rel="noreferrer" target="_blank">https://openjdk.org/jeps/395#Static-members-of-inner-classes</a>) and <br>
>>>> perhaps javac got a bit turned around over static contexts.<br>
>>>><br>
>>>> As an additional test case, make the constructor generic -- `public <br>
>>>> <U extends T> TypeParam ...` -- and cast obj to U rather than T -- <br>
>>>> still illegal.<br>
>>>><br>
>>>> Alex<br>
>>>><br>
>>>> On 2/1/2023 12:45 PM, Archie Cobbs wrote:<br>
>>>>> This program compiles without error:<br>
>>>>><br>
>>>>> import java.util.concurrent.atomic.*;<br>
>>>>> public class TypeParamStaticContext<T> extends AtomicReference<T> {<br>
>>>>>      public TypeParamStaticContext(Object obj) {<br>
>>>>>          super((T)obj);<br>
>>>>>      }<br>
>>>>> }<br>
>>>>><br>
>>>>> Yet according to my reading of the JLS, the appearance of T inside <br>
>>>>> the super() call should be disallowed:<br>
>>>>><br>
>>>>> §8.8.7.1 <<a href="http://8.8.7.1" rel="noreferrer" target="_blank">http://8.8.7.1</a>>:<br>
>>>>><br>
>>>>> An explicit constructor invocation statement introduces a static <br>
>>>>> context (§8.1.3 <br>
>>>>> <<a href="https://docs.oracle.com/javase/specs/jls/se19/html/jls-8.html#jls-8.1.3" rel="noreferrer" target="_blank">https://docs.oracle.com/javase/specs/jls/se19/html/jls-8.html#jls-8.1.3</a>>), which limits the use of constructs that refer to the current object. Notably, the keywords |this| and |super| are prohibited in a static context (§15.8.3 <<a href="https://docs.oracle.com/javase/specs/jls/se19/html/jls-15.html#jls-15.8.3" rel="noreferrer" target="_blank">https://docs.oracle.com/javase/specs/jls/se19/html/jls-15.html#jls-15.8.3</a>>, §15.11.2 <<a href="https://docs.oracle.com/javase/specs/jls/se19/html/jls-15.html#jls-15.11.2" rel="noreferrer" target="_blank">https://docs.oracle.com/javase/specs/jls/se19/html/jls-15.html#jls-15.11.2</a>>), as are unqualified references to instance variables, instance methods, and type parameters of lexically enclosing declarations (§6.5.5.1 <<a href="https://docs.oracle.com/javase/specs/jls/se19/html/jls-6.html#jls-6.5.5.1" rel="noreferrer" target="_blank">https://docs.oracle.com/javase/specs/jls/se19/html/jls-6.html#jls-6.5.5.1</a>>, §6.5.6.1 <<a href="https://docs.oracle.com/javase/specs/jls/se19/html/jls-6.html#jls-6.5.6.1" rel="noreferrer" target="_blank">https://docs.oracle.com/javase/specs/jls/se19/html/jls-6.html#jls-6.5.6.1</a>>, §15.12.3 <<a href="https://docs.oracle.com/javase/specs/jls/se19/html/jls-15.html#jls-15.12.3" rel="noreferrer" target="_blank">https://docs.oracle.com/javase/specs/jls/se19/html/jls-15.html#jls-15.12.3</a>>).<br>
>>>>><br>
>>>>> §6.5.5.1 <<a href="http://6.5.5.1" rel="noreferrer" target="_blank">http://6.5.5.1</a>>:<br>
>>>>><br>
>>>>> If a type name consists of a single /Identifier/, then the <br>
>>>>> identifier must occur in the scope of exactly one declaration of a <br>
>>>>> class, interface, or type parameter with this name (§6.3 <br>
>>>>> <<a href="https://docs.oracle.com/javase/specs/jls/se19/html/jls-6.html#jls-6.3" rel="noreferrer" target="_blank">https://docs.oracle.com/javase/specs/jls/se19/html/jls-6.html#jls-6.3</a>>), or a compile-time error occurs.<br>
>>>>><br>
>>>>> If the declaration denotes a type parameter of a generic class or <br>
>>>>> interface C (§8.1.2 <br>
>>>>> <<a href="https://docs.oracle.com/javase/specs/jls/se19/html/jls-8.html#jls-8.1.2" rel="noreferrer" target="_blank">https://docs.oracle.com/javase/specs/jls/se19/html/jls-8.html#jls-8.1.2</a>>, §9.1.2 <<a href="https://docs.oracle.com/javase/specs/jls/se19/html/jls-9.html#jls-9.1.2" rel="noreferrer" target="_blank">https://docs.oracle.com/javase/specs/jls/se19/html/jls-9.html#jls-9.1.2</a>>), then both of the following must be true, or a compile-time error occurs:<br>
>>>>><br>
>>>>>   *<br>
>>>>><br>
>>>>>     The type name does not occur in a static context (§8.1.3<br>
>>>>> <<a href="https://docs.oracle.com/javase/specs/jls/se19/html/jls-8.html#jls-8.1.3" rel="noreferrer" target="_blank">https://docs.oracle.com/javase/specs/jls/se19/html/jls-8.html#jls-8.1.3</a>>)<br>
>>>>><br>
>>>>>   *<br>
>>>>><br>
>>>>>     If the type name appears in a nested class or interface <br>
>>>>> declaration<br>
>>>>>     of C, then the immediately enclosing class or interface <br>
>>>>> declaration<br>
>>>>>     of the type name is an inner class of C.<br>
>>>>><br>
>>>>><br>
>>>>> What am I missing?<br>
>>>>><br>
>>>>> Thanks,<br>
>>>>> -Archie<br>
>>>>><br>
>>>>> -- <br>
>>>>> Archie L. Cobbs<br>
>>><br>
>>> <br>
> <br>
> <br>
</blockquote></div><br clear="all"><br>-- <br><div dir="ltr" class="gmail_signature">Archie L. Cobbs<br></div></div>