Proposal: Simplified syntax for dealing with parameterized types.

Reinier Zwitserloot reinier at zwitserloot.com
Mon Mar 23 13:16:04 PDT 2009


There are many more annoying issues with subtypes, most notably  
regarding behaviour of .equals(), and the the way one person's  
MapStringString isn't compatible with another's MapStringString,  
eventhough they are both really meant as just 'Map<String, String>'.

Your solution to this problem seems extremely overengineered, while  
the end-result is a patchy hack at best.

Just allowing Map<String, String> map = new HashMap<>(); - an idea  
that's been floated many times before, is something I'd strongly  
prefer, and it's much simpler.

  --Reinier Zwitserloot



On Mar 23, 2009, at 20:40, james lowden wrote:

>
> Proposal: Simplified syntax for dealing with parameterized types.
>
> AUTHOR(S):
>
> J. Lowden
>
> VERSION:
>
> 1.0    Initial version.
>
>
> OVERVIEW
>
> FEATURE SUMMARY:
>
> Declaring and instantiating parameterized types can be verbose  
> (resulting in expressions like "HashMap <String, String>" being  
> repeated throughtout one's code) and, due to the erasure-based  
> implementation of generics in Java, not necessarily type-safe.  The  
> code snippet below illustrates both:
>
>
>  HashMap <String, String> a = new HashMap <String, String> ();
>  HashMap b = new HashMap ();
>  b.put ("foo", new JFrame ());
>  a = b; // this is semantically wrong, but compiles
>
>
> In this case, the parameterization language ("<String, String>") is  
> repeated twice, which quickly becomes annoying if one is using a  
> large number of String-to-String hashes.  More dangerously, despite  
> "a" having been declared as a HashMap <String, String>, it is  
> possible to use it as a reference to a non-parameterized HashMap  
> which may contain objects of unexpected and semantically incorrect  
> types.  One way around this problem is by subclassing the  
> parameterized type, as in:
>
>
>  public class StringyMap extends HashMap <String, String> {
>  }
>
>
> The above example then becomes:
>
>
>  StringyMap a = new StringyMap ();
>  HashMap b = new HashMap ();
>  b.put ("foo", new JFrame ());
>  a = b; // this now causes a compiler error
>
>
> This both removes the repetition and causes the type-unsafe  
> assignments statement to generate a compiler error.  However, since  
> simply extending a class causes the loss of all but the default  
> constructor, in order to make StringyMap as useful as HashMap  
> <String, String>, we really need to do this:
>
>
>  public class StringyMap extends HashMap <String, String> {
>
>    public StringyMap () {
>    }
>
>    public StringyMap (int initialCapacity) {
>      super (initialCapacity);
>    }
>
>    public StringyMap (int initialCapacity, float loadFactor) {
>      super (initialCapacity, loadFactor);
>    }
>
>    public StringyMap (Map <String, String> m) {
>      super (m);
>    }
>
>  }
>
>
> This is an annoying heap of boilerplate code, especially seeing that  
> verbosity was one of the issues we were trying to address.   
> Therefore, the new syntax being proposed is something along the  
> lines of:
>
>  public class X = Y <list of type parameters>;
>
> which would be exactly equivalent to:
>
>  public class X extends Y <list of type parameters> {
>
>    // constructors
>
> }
>
> with constructors matching the signatures of the superclass  
> constructors automatically generated that simply pass all the  
> parameters along to the superclass constructor.
>
> This could also be done with interfaces.  Since interfaces do not  
> support constructors, the mapping is simpler, as we simply leave the  
> automatic constructor creation out:
>
>  public interface X = Y <list of type parameters>;
>
> is equivalent to:
>
>  public interface X extends Y <list of type parameters> {}
>
>
> Java currently requires each top-level public class or interface to  
> be declared in its own source file.  When working with multiple  
> parameterized types, this could result in a large number of one-line  
> source files that may be inconvenient to deal with.  Therefore, I  
> also propose the creation of an optional special source file in each  
> package that can be used to contain multiple such type definitions.   
> This file would be named something like "param-types.java" (the  
> specific name doesn't matter as long as it is A) standardized and B)  
> not a legal Java identifier, so we avoid collisions), and all public  
> classes or interfaces defined in it would be compiled as though they  
> were top-level class files in the given package.  The "param- 
> types.java" file would be restricted to containing classes/ 
> interfaces defined using the new syntax described above; this file  
> is intended as a convenience mechanism to support the features  
> described above, not a mechanism for
> cramming all of one's code into one hideously-long source file.
>
> Although not a principal goal of this proposal, this also provides  
> an easy mechanism for enforcing type safety between two types that  
> have the same parameters but are not intended to be  
> interconvertible.  For example:
>
> public interface ListOfThingsToNameTheBaby = List <String>;
> public interface ListOfAnnoyingInternetAcronyms = List <String>;
>
> ListOfThingsToNameTheBaby a;
> ListOfAnnoyingInternetAcronyms b;
>
> a = b; // raises a compiler error, since these are not assignable
>
>
> Note that there is potential for confusion if the two types were  
> actually meant to be interconverible (i.e., ListOfNamesForBabies and  
> ListOfThingsToNameTheBaby).
>
>
> MAJOR ADVANTAGE:
>
> It becomes easier and more elegant to create reusable, robust  
> parameterized types.
>
>
> MAJOR BENEFIT:
>
> Readability of code that makes extensive use of parameterized types  
> is improved.  Although the general erasure-related issues with type- 
> safety of generics are not eliminated, this provides a  
> straightforward mechanism for working with more robust parameterized  
> types.
>
>
> MAJOR DISADVANTAGE:
>
> Programmers (especially those working on distributed projects) may  
> inadvertantly end up defining two types meant to be "the same thing"  
> that are not mutually assignable, as in:
>
> public class ListOfNamesForBabies = ArrayList <String>;
> public class ListOfThingsToNameTheBaby = ArrayList <String>;
>
> ListOfNamesForBabies a;
> ListOfThingsToNameTheBaby b;
>
> a = b; // does not compile
>
>
> Note that this is only a problem in cases where the types are  
> intended to be equivalent; see the ListOfAnnoyingInternetAcronyms/ 
> ListOfThingsToNameTheBaby example above.
>
>
> ALTERNATIVES:
>
> Write strings the old way by using concatenations or using builders.
>
>
> EXAMPLES
>
> SIMPLE EXAMPLE:
>
> --- creating a file named StringyMap.java in package blah
>
>  package blah;
>
>  // various import statements
>
>  public class StringyMap = HashMap <String, String>;
>
>
> --- is equivalent to what would currently result from the following:
>
>  package blah;
>
>  // various import statements
>
>  public class StringyMap extends HashMap <String, String> {
>
>    public StringyMap () {
>    }
>
>    public StringyMap (int initialCapacity) {
>      super (initialCapacity);
>    }
>
>    public StringyMap (int initialCapacity, float loadFactor) {
>      super (initialCapacity, loadFactor);
>    }
>
>    public StringyMap (Map <String, String> m) {
>      super (m);
>    }
>
>  }
>
> ADVANCED EXAMPLE:
>
> --- creating a file named param-types.java in package blah
>
>  package blah;
>
>  // various import statements
>
>  public class StringyMap = HashMap <String, String>;
>  public interface ListOfNames = List <String>;
>
> --- is equivalent to what would currently result from defining the  
> StringyMap class in the previous example
> --- as well as the following:
>
>  package blah;
>
>  // various import statements
>
>  public interface ListOfNames extends List <String> {}
>
>
> DETAILS
>
> SPECIFICATION:
>
> The new syntax can be handled entirely via compiler modifications.   
> Since this proposal consists entirely of syntactic sugar atop the  
> existing type system and uses a syntax that currently has no meaning  
> in Java, it should not have any affect on the meaning of any current  
> feature of the Java Programming Language.
>
>
> COMPILATION:
>
> Compilation of this new feature would consist of de-sugaring two new  
> types of declarations.  For interfaces, the following:
>
> [modifier_list] interface [name] = [superinterface]  
> <list_of_types. . .>;
>
> is de-sugared to:
>
> [modifier_list] interface [name] extends [superinterface]  
> <list_of_types. . .> {}
>
>
> Classes are a bit more complex:
>
> [modifier_list] class [name] = [superclass] <list_of_types. . .>;
>
> is de-sugared to:
>
> [modifier_list] class [name] extends [superclass]  
> <list_of_types. . .> {
>
>  [constructors]
>
> }
>
> Where the [constructors] block consists of one "wrapped" constructor  
> for each public or protected constructor in the superclass.  Thus,  
> for each such constructor in the superclass:
>
>  [public/protected] [superclass] ([constructor_args. . .]);
>
> A "wrapper" constructor would be generated as follows:
>
>  [public/protected] [name] ([constructor_args. . .]) {
>    super ([constructor_args. . .]);
>  }
>
>
> Finally, when resolving dependencies, if the compiler doesn't find a  
> class or source file for a top-level class in the expected location,  
> the compiler would examine "param-types.java" in the package- 
> appropriate directory to see if it is defined there.  Only classes  
> and interfaces defined using the syntax described here are permitted  
> in the "param-types.java"; any "traditional" class or interface  
> definition in this file results in a compiler error.
>
>
> TESTING:
>
> This feature can be tested in the same manner as any other form of  
> class or interface declaration.
>
> LIBRARY SUPPORT:
>
> None required.
>
> REFLECTIVE APIS:
>
> This should be automatic, as the current reflective APIs will  
> correctly identify the class or interface.
>
> OTHER CHANGES:
>
> None.
>
> MIGRATION:
>
> Replace current use of parameterized types where feasible.
>
>
> COMPATIBILITY
>
> BREAKING CHANGES:
>
> None. The proposed syntax currently causes compiler errors.
>
> EXISTING PROGRAMS:
>
> No changes.
>
>
> REFERENCES
>
> EXISTING BUGS:
>
> None that I am aware of.
>
> URL FOR PROTOTYPE (optional):
>
> None thus far; work-in-progress.
>
>
>
>




More information about the coin-dev mailing list