Importing Static Members in the Javatm Programming Language


Summary


The proposal is to introduce variants of the import statement into the
JavaTM programming language so as to allow importation of static methods
and fields in the manner that classes and interfaces can now be imported.
We propose that a declaration of the form


        import static TypeName . Identifier ;


should import into the current compilation unit the name specified by
the Identifier, which must be a static member of the class or interface
named by TypeName.  We also propose that a declaration of the form


        import static TypeName . * ;


should import into the current compilation unit the names of all
static members of the class or interface named by TypeName.


This proposal requires no changes to the JVM; it involves only the
processing of additional forms of import declarations and an extended
interpretation of simple names at compile time.


Motivation


This proposal addresses two problems in current practice.


(1) Mathematical functions


First is the customary notation for mathematical functions such as
"abs" and "sqrt" and "max".  In the Java programming language,
when applying such functions to arguments of type float or double,
it is necessary to write


        Math.abs(x)     Math.sqrt(x)    Math.max(a, b)


where "Math" refers to the class whose full name is "java.lang.Math".
This is undesirably verbose for numerical code compared to what
one can write in languages such as C, Fortran, and Pascal:
        
        abs(x)          sqrt(x)         max(a, b)

(2) Named constants


It is desirable in many situations to have a set of named constants
such as


        public static final int RED = 0;
        public static final int YELLOW = 1;
        public static final int GREEN = 2;


for a traffic light, and it is often deemed undesirably verbose simply
to put them in some utility class TrafficLightand refer to them always
as TrafficLight.RED, TrafficLight.YELLOW, and TrafficLight.GREEN ;
therefore some programmers have taken to defining such constants in
a utility *interface* and then "importing" such constants into a class
by the strategem of declaring the class to "implement" the (otherwise
vacuous) interface.  But, inheriting from an interface to get access to
constants in an implementation is a publicly visible operation, and is therefore
subject to all the rules for binary compatibility when modifying the constatnts. 
Moreover, it requires all other implementations to inherit the same interface and the same constants,
even though that other implementation may not require them.


This proposal provides a more straightforward mechanism: define the
constants in a utility class, and then import them:


        import static TrafficLight.*;


Another advantage: such a declaration is needed only once per
compilation unit rather than once per class.


Note:  assuming the accompanying proposal for enumerations is adopted


       public class TrafficLight {
           ...
           public enum Color {RED, YELLOW, GREEN}
           ...
       }



Then one has the the choices of:


(a) Writing import mypackage.TrafficLight;  and TrafficLight.Color.RED .
(b) Writing import mypackage.TrafficLight.Color; and Color.RED .
(c) Writing import static mypackage.TrafficLight.Color.*; and RED.





Rationale for Choice of Syntax



One might well ask why the keyword static should appear in the
import declaration, for the compiler can easily tell what is to be
imported without the presence of that keyword.  There are two reasons:


(a) To distinguish visually the importation of members, such as
methods and fields, from the importation of classes and interfaces
(while it easy for the compiler to tell them apart, it is harder
for people, so a redundant visual cue is useful).


(b) To remind the reader (and the programmer) that only static members
can be so imported.  (It does not work to try to refer to an instance
member of an arbitrary class by a simple name, because a simple name
fails to supply necessary information as to which instance of the
class is involved.)



Full Proposal



Here we describe the necessary modifications the the Java Language
Specification (JLS), second edition, for this proposal.


Augment the syntax of the import statement (JLS 7.5) to allow two
more possibilities:


        ImportDeclaration:
                SingleTypeImportDeclaration
                TypeImportOnDemandDeclaration
                SingleStaticImportDeclaration
                StaticImportOnDemandDeclaration


        SingleStaticImportDeclaration:
                import static TypeName . Identifier ;


        StaticImportOnDemandDeclaration:
                import static TypeName . * ;


  The TypeName must be the canonical name of a class or interface type;
  a compile-time error occurs if the named type does not exist.  The named
  type must be accessible or a compile-time error occurs.  For a
  single-static-import declaration, the Identifier must name a static
  member of the named type; a compile-time error occurs if there is
  no member of that name or if the named member is not accessible.


  A single-static-import declaration in compilation unit c of
  package p that imports a member named n shadows the declarations of:


  * any top level type named n declared in another compilation unit of p.


  * any type named n imported by a type-import-on-demand declaration in c.


  * any static member named n imported by a static-import-on-demand declaration
in c.


(The rules for a single-type-import declaration in JLS 7.5.1 must have
a similar third bullet added.)


  A static-import-on-demand declaration never causes any other declaration
  to be shadowed.



(These rules also need to be added to JLS 6.3.1.)


  If two single-static-import declarations in the same compilation unit
  attempt to import members with the same simple name, then a compile-time
  error occurs, unless the two members are the same member of the same type,
  in which case the duplicate declaration is ignored.


  If a single-static-import declaration imports a member whose simple
  name is n, and the compilation unit also contains a single-type-import
  declaration that imports a type whose simple name is n, a compile-time
  error occurs.  (This error occurs even if both declarations refer to
  the same type, on the grounds that it is confusing to use two different
  mechanisms to redundantly import the same type.)


  If a single-static-import declaration imports a member whose simple
  name is n, and the compilation unit also declares a top level type
  whose simple name is n, a compile-time error occurs.


Option: We could choose to have another set of automatic imports (JLS
7.5.3) by specifying that each compilation unit, besides automatically
importing all public type names in package java.lang, should also
automatically import all public static members of
java.lang.Math
thereby making abs sqrt and PI automatically available in all programs.


The rules in JLS 6.5.2 for classification of an AmbiguousName that is
a simple name must be augmented.  Between the third and fourth
diamond-bulleted subparagraphs, add:


     <> Otherwise, if a static member of that name is declared
        in the compilation unit containing the Identifier by a
        single-static-import-declaration, then the AmbiguousName
        is reclassified as a Typename, a MethodName, or an
        Expressionname according to whether that static member
        is a class or interface, a method, or a field.



Also, the fifth and sixth diamond-bulleted subparagraphs are replaced by
these three paragraphs:


     <> Otherwise, if a type of that name is declared by exactly one
        type-import-on-demand declaration of the compilation unit
        containing the Identifier, and not by any static-import-on-demand
        declaration of the compilation unit containing the Identifier,
        then the AmbiguousName is reclassified as a TypeName.


     <> Otherwise, if a member of that name is declared by exactly one
        static-import-on-demand declaration of the compilation unit
        containing the Identifier, and not by any type-import-on-demand
        declaration of the compilation unit containing the Identifier,
        then the AmbiguousName is reclassified as a TypeName, a MethodName,
        or an Expressionname according to whether that static member
        is a class or interface, a method, or a field.


     <> Otherwise, if a type of that name is declared by more than one
        type-import-on-demand declaration of the compilation unit
        containing the Identifier, or a member of that name is declared by
        more than one static-import-on-demand declaration of that compilation
        unit, or a type of that name is declared by a type-import-on-demand
        declaration of that compilation unit and a member of that name is
declared
        by a static-import-on-demand declaration of that compilation unit,
        then a compile-time error occurs.



The rules in JLS 6.5.5.1 for the meaning of a simple type name must
be augmented.  The fourth bulleted paragraph is replaced by:


      * Otherwise, if a type with that name is declared in the current
        compilation unit, either by a single-type-import declaration,
        by a single-static-import declaration, or by a declaration
        of a class or interface type, then the simple type name denotes
        that type.



Also, the sixth and seventh bulleted paragraphs are replaced by these
three paragraphs:


      * Otherwise, if a type of that name is declared by exactly one
        type-import-on-demand declaration of the compilation unit
        containing the Identifier, and not by any static-import-on-demand
        declaration of the compilation unit containing the Identifier,
        then the simple type name denotes that type.


      * Otherwise, if a type of that name is declared by exactly one
        static-import-on-demand declaration of the compilation unit
        containing the Identifier, and not by any type-import-on-demand
        declaration of the compilation unit containing the Identifier,
        then the simple type name denotes that type.


      * Otherwise, if a type of that name is declared by more than one
        type-import-on-demand declaration of the compilation unit
        containing the Identifier, or a member of that name is declared by
        more than one static-import-on-demand declaration of that compilation
        unit, or a type of that name is declared by a type-import-on-demand
        declaration of that compilation unit and a member of that name is
declared
        by a static-import-on-demand declaration of that compilation unit,
        then the name is ambiguous as a type name; a compile-time error occurs.



The rules in JLS 6.5.6.1 for the meaning of a simple expression name must
be augmented.  In the second bulleted paragraph, the second and third
diamond-bulleted subparagraphs are replaced by these five subparagraphs:


     <> Otherwise, if the class has a member field of that name:


        :: If the single member field of that name is declared final ...


        :: Otherwise, the expression name denotes a variable ...


     <> Otherwise, if a field of that name is declared by exactly one
        nonredundant single-static-import declaration of the compilation unit
        containing the Identifier:


        :: If the static field of that name is declared final or the
           field is a member of an interface ...


        :: Otherwise, the expression name denotes a variable ...


     <> Otherwise, if a field of that name is declared by exactly one
        static-import-on-demand declaration of the compilation unit
        containing the Identifier:


        :: If the static field of that name is declared final or the
           field is a member of an interface ...


        :: Otherwise, the expression name denotes a variable ...


     <> Otherwise, if a field of that name is declared by more than one
        static-import-on-demand declaration of the compilation unit
        containing the Identifier, then the name is ambiguous as
        an expression name; a compile-time error occurs.


     <> Otherwise, the name is undefined as an expression name;
        a compile-time error occurs.


In the third bulleted paragraph, the second diamond-bulleted
subparagraph is replaced by these five subparagraphs:


     <> Otherwise, if the interface has a member field of that name,
        the expression name denotes the value of the member field ...


     <> Otherwise, if a field of that name is declared by exactly one
        nonredundant single-static-import declaration of the compilation unit
        containing the Identifier, the expression name denotes the value
        of the member field ...


        :: If the static field of that name is declared final or the
           field is a member of an interface ...


        :: Otherwise, the expression name denotes a variable ...


     <> Otherwise, if a field of that name is declared by exactly one
        static-import-on-demand declaration of the compilation unit
        containing the Identifier:


        :: If the static field of that name is declared final or the
           field is a member of an interface ...


        :: Otherwise, the expression name denotes a variable ...


     <> Otherwise, if a field of that name is declared by more than one
        static-import-on-demand declaration of the compilation unit
        containing the Identifier, then the name is ambiguous as
        an expression name; a compile-time error occurs.


     <> Otherwise, the name is undefined as an expression name;
        a compile-time error occurs.


The second sentence of JLS section 6.5.7.1 is replaced by:


  The Identifier must name either at least one method of a class or interface
  within whose declaration the Identifier appears, or a method imported
  by a single-static-import declaration or static-import-on-demand
  declaration within the compilation unit within which the Identifier appears.


JLS section 8.4.6.1 is amended by adding this sentence:


  An instance method hides all methods of the same signature that
  may be imported by single-static-import and static-import-on-demand
  declarations.



JLS section 8.4.6.2 is amended by adding this sentence:


  A static method also hides all methods of the same signature that
  may be imported by single-static-import and static-import-on-demand
  declarations.



JLS section 15.12.2.1, the paragraph after the two bulleted paragraphs
has a sentence added to it, so that the whole paragraph reads as follows:


  The class or interface determined by the process described in section
  15.12.1 is searched for all method declarations applicable to this
  method invocation; method definitions inherited from superclasses and
  superinterfaces are included in this search.  In addition, if the
  method invocation has, before the left parenthesis, a MethodName of
  the form Identifier, then the search process also examines all methods
  that are (a) imported by single-static-import declarations and
  static-import-on-demand declarations within the compilation unit
  within which the method invocation occurs, and (b) not hidden at the
  place where the method invocation appears.



Copyright 2001-2002 Sun Microsystems, Inc., 901 San Antonio Road, Palo Alto, California 94303 U.S.A. All rights reserved.