[External] : Re: Can not call a private method, no idea why ?

Maurizio Cimadamore maurizio.cimadamore at oracle.com
Thu Jan 21 13:03:50 UTC 2021


>     I don't believe that's the right analogy; this is:
>
>     ```
>     import java.util.function.Function;
>
>     class Test {
>       private void greet() { System.out.println("hello"); }
>
>       <X extends Test> void test(X x) {
>         x.greet();
>       }
>     }
>     ```
>
>     Which also fails, no wildcards around this time.
>
>     When you access a member on a `? extends T` you get back a
>     captured variable, which is a fresh type variable with some
>     bounds. As per JLS 4.4 the members of a type variable X extends A
>     & I1 ... In are the members of the intersection type (A, I1 ..
>     In). In the definition of intersection type in JLS 4.9 you will
>     see that only public members are allowed.
>
>     This decision comes from the fact that type-variables have a "for
>     all" spirit to them - when you write something like x.e, and x is
>     of type X (with X a type variable) the intent of the language is
>     for x.e to either be valid _for all_ instantiations of X, or to be
>     rejected. Without this rule, it would be very easy to write a
>     generic class which can be instantiated in ways that make it break
>     some (runtime) assumptions.
>
>
> Given that private method are not dynamically linked, i don't see how 
> this is issue at runtime.
>
> Back to the first example, if you introduce a 'var' in the middle, it 
> will compile
>
> class Test {
>   private void greet() { System.out.println("hello"); }
>
>   void test(Function<? super Object, ? extends Test> f) {
>     f.apply(null).greet();  // nope
>     var t = f.apply(null);
>     t.greet();                   // yes !
>   }
> }
>
> so i don't think itcan break some runtime assumptions.

I think your example is subtly misleading - you are using `var` and 
`var` has special normalization for avoiding captured variables - which 
means that accessing apply(null).greet() and t.greet() have completely 
different static types.

To back off form this specific example, think of this:

public class Box<X extends Foo> {
    X x;

    Box(X x) { this.x = x; }

    void m() {
        x. ???
    }
}

What are the valid member access for "x" ?

Say that Box and Foo are in the same package - can I access all members 
of "Foo" ? Note that this Box class can be used from a completely 
different package, so there will be runtime issues if we bake in 
assumptions on which members can be accessed from the type variable.

In other words - if Box<T> is a well-formed type, I want a guarantee 
that no bad stuff can happen at runtime (yes, there can be unchecked 
casts and all that - but let's assume that all the code compiled w/o 
warnings). And if you allow access to anything other than public members 
you have no such guarantee.

I sympathize with your argument: at the end of the day, when you have X 
<: Foo, you can always widen (e.g. assign) X to Foo (w/o warnings) and 
take it from there, and all restrictions are gone - so maybe this is 
excessive hand-holding on the language-side - but I was trying to 
explain the rationale behind the rules - it is pretty common when 
dealing with parametric polymorphism to think of membership of a 
type-variable X in a "for all" semantics - e.g. the intersection of 
members that are available in all instantiations of X; so, for the 
language (and the compiler) X <: Foo and Foo are two very different 
types, with very different membership rules.

Maurizio


>
>     Maurizio
>
>
> Rémi
>
>
>
>
>
>             Maurizio
>
>
>         Rémi
>
>
>             On 21/01/2021 10:53, Anna Kozlova wrote:
>
>                 Hi Remi,
>
>                 type of  `map.apply(null)` is capture of `? extends
>                 IOBug` and thus it has no access to private methods of
>                 IOBug. Do I miss something?
>
>                 Thanks,
>                 Anna
>
>                 On Thu, Jan 21, 2021 at 9:34 AM Remi Forax
>                 <forax at univ-mlv.fr <mailto:forax at univ-mlv.fr>> wrote:
>
>                     The following code doesn't compile.
>                     No idea why ?
>
>                     public interface IOBug {
>                       private IOBug foo() {
>                         return this;
>                       }
>
>                       default IOBug flatMap(Function<? super Object, ?
>                     extends IOBug> map) {
>                         return map.apply(null).foo();
>                                                ^------
>                       }
>                     }
>
>                     It works if foo is declared as a default method
>                     instead of a private method.
>
>                     regards,
>                     Rémi
>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.java.net/pipermail/compiler-dev/attachments/20210121/c4f38cfb/attachment.htm>


More information about the compiler-dev mailing list