On 12/18/2015 12:20 AM, John Rose wrote:
On Dec 17, 2015, at 6:01 PM, John Rose <john.r.r...@oracle.com
<mailto:john.r.r...@oracle.com>> wrote:
I think I would prefer case 2. The user model is PUBLIC is the
weakest (non-empty) access mode available to bytecode behaviors. As
such it respects the LC's position in the module graph, and
excludes module-private, package-private, and class-private.
UNCONDITIONAL is the special thing provided by publicLookup, which
ignores the module graph. Then PACKAGE opens up the LC's package,
MODULE opens up the LC's module, and PRIVATE opens up the LC itself
(plus its nestmates). Feels pretty good, especially since MODULE
and PACKAGE continue to have a parallel sense of restriction.
What do you think?
So I caught you in the hall and we talked, and this seems agreeable
to us both, perhaps with a name change to UNCONDITIONAL, and also a
distinctionbetween PUBLIC and QUALIFIED (as you originally proposed).
To try and tease out some symmetry here:
- Always, any type T is accessible to itself, when T = LC.
- PACKAGE mode: Any type T is accessible (within its own package), when
PACKAGE(T) = PACKAGE(LC).
- MODULE mode: A public type T is accessible (within or beyond its
package), when MODULE(T) = MODULE(LC).
- QUALIFIED mode: A public type T is accessible beyond its module, when
IS_CE(T, LC),
where IS_CE(T, LC) = IS_CONDITIONALLY_EXPORTED(PACKAGE(T),
MODULE(LC)) and MODULE(LC) READS MODULE(T).
- PUBLIC mode: A public type T is accessible beyond its module friends
when IS_UE(T, LC),
where IS_UE(T, LC) = IS_UNCONDITIONALLY_EXPORTED(PACKAGE(T)) and
MODULE(LC) READS MODULE(T).
These conditions can be tested independently. PACKAGE implies MODULE,
but everything else is disjoint.
Also:
- UNCONDITIONAL: In this mode, a type T is accessible if
IS_UNCONDITIONALLY_EXPORTED(PACKAGE(T)), regardless of LC.
- PRIVATE/PROTECTED: These protection modes apply only to non-types (JVM
does not enforce "private" on classes).
- NOACCESS: This is not a mode but the absence of any combination of
modes; no access is allowed.
So let's recap full power lookups:
- Start with an arbitrary class in an arbitrary module calling
MethodHandles.Lookup.lookup() to get a "full power" lookup object L. L's
lookup modes are PUBLIC + QUALIFIED + MODULE + PROTECTED + PACKAGE +
PRIVATE.
- The arbitrary class obtains a Class object representing class A, then
calls L.in(A). If L's lookup class cannot access A (for example, A is
package-private in a different package than L's lookup class), then the
resulting lookup object has lookup mode NOACCESS. Otherwise:
-- If A is in a different module than L's lookup class, then the
resulting lookup object has lookup mode NOACCESS.
-- If A is in the same module as L's lookup class, but a different
package, then the resulting lookup object has lookup modes no greater
than PUBLIC + QUALIFIED + MODULE.
-- If A is in the same module as L's lookup class, and in the same
package, but A is a different class than L's lookup class, then the
resulting lookup object has lookup modes no greater than PUBLIC +
QUALIFIED + MODULE + PACKAGE.
-- If A is nested in the same package member as L's lookup class,
then the resulting lookup object has lookup modes no greater than PUBLIC
+ QUALIFIED + MODULE + PACKAGE + PRIVATE.
-- If A is the same class as L's lookup class, then the resulting
lookup object has the same lookup modes as L.
The publicLookup should have UNCONDITIONAL and PUBLIC set. An
original full-power lookup does *not* have UNCONDITIONAL set, just
PUBLIC. The purpose of UNCONDITIONAL is to allow publicLookup to be
unconcerned (as documented) about its LC. We can restore LC to be
java.lang.Object.
Since PUBLIC is just UNCONDITIONAL with a concern for readability, it's
surprising that publicLookup cares about PUBLIC.
Before saying any more about that, let me take a small detour. I seem to
recall an intent to specify the public lookup object as representing an
(undisclosed) lookup class in the unnamed module ... if so, then since
the unnamed module reads all named modules by decree, we have
UNCONDITIONAL+PUBLIC as trivially equal in access power to PUBLIC, and
we don't need UNCONDITIONAL at all ... if not, then publicLookup could
be UNCONDITIONAL only.
Returning from the detour ... does the public lookup object have PUBLIC
solely so that it can teleport to give new lookup objects which drop
UNCONDITIONAL but still retain the interesting PUBLIC mode?
Proceeding to walk through a publicLookup:
- Start with an arbitrary class in an arbitrary module calling
MethodHandles.Lookup.publicLookup() to get a public lookup object PL.
PL's lookup mode is UNCONDITIONAL [+ PUBLIC?].
- The arbitrary class obtains a Class object representing class A, then
calls PL.in(A). If PL's lookup class cannot access A [I'm not sure what
PL's lookup class is, but it seems plausible that it can't access A],
then the resulting lookup object has lookup mode NOACCESS. Otherwise:
-- If A is in a different module than PL's lookup class, then the
resulting lookup object has lookup mode UNCONDITIONAL. ???
-- If A is in the same module as PL's lookup class, then the resulting
lookup object has lookup mode PUBLIC. ???
As an odd use case, a stripped lookup with only PACKAGE modes
will be able to see any package-mate T of LC, and any package-private
API point T.M, but it won't be able to query anything *outside* of the
package of T. Unfortunately, it also won't be able to query any public
member T.M, unless the PUBLIC bit is present. So I suppose stripping
MODULE and QUALIFIED, leaving PUBLIC and PACKAGE, would
provide useful access to T.M even if M were public.
I think there's an "old" meaning of PUBLIC floating around here. Now
that PUBLIC pertains to public types _in unconditionally exported
packages_, it shouldn't relate to intra-package access, since for such
access you don't care if the package is exported. It's now MODULE that
accesses public types within the module, so arguably, access to a public
member M of package-mate T should be possible with lookup modes
MODULE+PACKAGE, not PUBLIC+PACKAGE.
Alex