Forum Stats

  • 3,853,788 Users
  • 2,264,269 Discussions
  • 7,905,444 Comments

Discussions

Generics that require no additional syntax

843793
843793 Member Posts: 41,732 Green Ribbon
edited Jul 6, 2002 11:49PM in Generics
I want to elaborate on my suggestion in the "bytecode" thread. The thing that makes C++ impenetrable, in my opinion, is the dense syntax. I'd oppose importing this syntax into Java.

In the "bytecode" thread, I propose a way to implement generics within the current Java syntax -- with no new brackets, no brackets within brackets, no meta variables, etc...

Already the compiler is doing something that might be called "run-time anticipation". (Is there a technical term for this?) If-statements, for example, normally involve run-time decision-making, but in the following case, the compiler anticipates the run-time decision and suppresses the println invocation:

if( false) {
System.out.println( "Trace!");
}

Given that the condition is a constant, the compiler is smart enough to know that there is no need to postpone the decision to run-time.

One can find other ways where the compiler anticipates run-time activities -- the detection of "unreachable code" errors, for example. The compiler also does more than is strictly called for when it treats Object methods like .equals as implicit in interface declarations -- e.g.,

List a = new ArrayList();
List b = new ArrayList();

boolean c = ( a.equals( b));

works, although the equals method is nowhere defined in the List interface.

I propose that generics be implemented in a similar fashion. A "setType( Class iCl)" method would be added to the Collection class. The compiler, as an option, would detect this "setType", just as it detects the "false" in the if-statement above. It would then "optimize" the Collection by automatically inserting compile-time type-checking at each
"add" or "addAll" invocation.

If the compiler option were turned off, then the compiler would treat "setType" as a normal method, and the Collection itself would perform type-checking at run-time.

Comments?
«134

Comments

  • 843793
    843793 Member Posts: 41,732 Green Ribbon
    Your approach presumes that generics is only applied to types implementing the Collection interface (or it requires a special case method for every type to which you want to extend the approach).
    So to permit compile time checking of Map classes would require another set of rules embedded in the compiler.
  • 843793
    843793 Member Posts: 41,732 Green Ribbon
    Well, then, just add a new interface, similar to "Comparable" or "Runnable". Call it "Typeable". Anything implementing a Typeable interface gets an automatic compiler assist. The compiler would then look for the setType() and substitute compile-time type checking. Those who didn't want this assist could turn off the compiler option, in which case the setType would be compiled as a normal method invocation, and type-checking would occur at run time. This would please just about everybody, while keeping the Java syntax uncluttered and readable.

    I've read many of the other threads in this forum, and I've noticed a trend. The pro-generics people use the need for cast-free Collections as their selling point, and they start with very simple examples -- e.g., List<int>. This is the wedge used to convince us that generics are needed. But as soon as we are convinced, the discussion shifts away from Collections and the examples become more complex..

    Maybe I'm slow, but it takes me several minutes of staring to figure out what the intent is, in some of these examples. The problem is, the syntax introduces a whole new level of abstraction. So when I see that <T implements X>, I can no longer think "Integer" or "StringBuffer" or "JTextArea" -- instead, I have to think "X", and all of the things that "X" could ever possibly represent. My eyes glaze over, which is exactly what happens when I look at C++ code.

    I'm told that I don't have to use generics if I don't want to. Fine, but I will still have to read code written by other people who DO use generics! If I can't make sense of their code, I'm adversely affected., whether or not I use generics myself.

    If runtime-anticipation using existing Java constructs does not solve every problem, well, there's still the wrapper approach -- write the bulk of the code for the Object type, then put typesafe wrappers around the class when it comes time to get specific.
  • 843793
    843793 Member Posts: 41,732 Green Ribbon
    Well, then, just add a new interface, similar to
    "Comparable" or "Runnable". Call it "Typeable".
    How do you describe to the compiler which arguments need to be verified? In the case of a Map you would need to specify the type for the key as well as that for the values. The generics proposal provides a language for descibing these rules.
    This would please just about everybody, while keeping
    the Java syntax uncluttered and readable.
    I think very few would be pleased by this approach.
    So when I see that
    <T implements X>, I can no longer think "Integer" or
    "StringBuffer" or "JTextArea" -- instead, I have to
    think "X", and all of the things that "X" could ever
    possibly represent.
    No you need only concern yourself with the properties that X has, not whatever additional fields/methods may be present in an actual instance of T.
    I'm told that I don't have to use generics if I don't
    want to. Fine, but I will still have to read code
    written by other people who DO use generics! If I
    can't make sense of their code, I'm adversely
    affected., whether or not I use generics myself.
    This is true. However once you have made the effort to understand generics, code which uses it well will be easier to comprehend than the non generic equivalent. There is a cost, but the pay back is bigger.
    If runtime-anticipation using existing Java constructs
    does not solve every problem, well, there's still the
    wrapper approach -- write the bulk of the code for the
    Object type, then put typesafe wrappers around the
    class when it comes time to get specific.
    Those runtime wrappers often get typos in them which are not detected until run time.

    Eliminating the floating point types from Java would end the main source of misconceptions (judging by traffic on cljp), but no one seriously proposes doing it.
  • 843793
    843793 Member Posts: 41,732 Green Ribbon
    Well, then, just add a new interface, similar to
    "Comparable" or "Runnable". Call it "Typeable".
    Anything implementing a Typeable interface gets an
    n automatic compiler assist. The compiler would then
    look for the setType() and substitute compile-time
    type checking. Those who didn't want this assist
    could turn off the compiler option, in which case the
    setType would be compiled as a normal method
    invocation, and type-checking would occur at run time.
    This would please just about everybody, while keeping
    the Java syntax uncluttered and readable.
    I don't think the compiler could do this. If it could, it could solve the Halting Problem, which is not solvable.

    I've read many of the other threads in this forum, and
    I've noticed a trend. The pro-generics people use
    the need for cast-free Collections as their selling
    point, and they start with very simple examples --
    e.g., List<int>. This is the wedge used to convince
    us that generics are needed. But as soon as we are
    convinced, the discussion shifts away from
    Collections and the examples become more complex..
    As far as I know, everyone agrees that generics is not needed. It's simply helpful in writing correct programs.

    Maybe I'm slow, but it takes me several minutes of
    staring to figure out what the intent is, in some of
    these examples. The problem is, the syntax introduces
    a whole new level of abstraction. So when I see that
    <T implements X>, I can no longer think "Integer" or
    "StringBuffer" or "JTextArea" -- instead, I have to
    think "X", and all of the things that "X" could ever
    possibly represent. My eyes glaze over, which is
    exactly what happens when I look at C++ code.
    This is how polymorphism, the core of object-oriented programming, works. When you see the line
    X x = getX();
    the returned reference need only implement the X interface. Again, you have to think of all the things an "X" reference could point to. I'm not convinced that generics is any more difficult than ordinary object-oriented programming.

    In fact, generics code is more readable because without it you end up using Object references all over the place. You then need to think of all the things an Object reference could point to, which is anything. Generics allows programmers to better describe what types methods are accepting or returning.
  • 843793
    843793 Member Posts: 41,732 Green Ribbon
    0( CharlesObler Reply 2 Apr 5, 2002 11:40 AM:
    Well, then, just add a new interface, similar to "Comparable" or "Runnable". Call it "Typeable".
    )0

    1( mthornton Reply 3 Apr 5, 2002 12:39 PM:
    How do you describe to the compiler which arguments need to be verified? In the case of a Map you would need to specify the type for the key as well as that for the values. The generics proposal provides a language for descibing these rules.
    )1

    2( Charles Obler Reply 5:
    Thanks for your replies and your interest.

    Map could be handled with a two-operand version of the setType(), the first operand specifying the key type and the second, the value type.

    I think all my proposal really changes is the syntax. The new generic code would be LOOK like normal Java. My solution avoids the angle-brackets and looks like run-time code -- and might even BE run-time code, depending on the compiler option. It's easier to understand generics from a run-time perspective, because we have that already -- anybody today can write a setType() method and their own add() and addAll() methods and get the generics effect.

    If there is really no semantic difference between angle-brackets and the less conspicuous setType() pseudo-method approaches, then the latter is just as feasible as the former. If the insolubility of the Halting Problem halts the latter approach, then it halts the former approach as well.
    )2



    0( CharlesObler Reply 2 Apr 5, 2002 11:40 AM:
    This would please just about everybody, while keeping the Java syntax uncluttered and readable.
    )0

    1( mthornton Reply 3 Apr 5, 2002 12:39 PM:
    I think very few would be pleased by this approach.
    )1

    2( Charles Obler Reply 5:
    Why are you NOT pleased with it?
    )2



    0( CharlesObler Reply 2 Apr 5, 2002 11:40 AM:
    I'm told that I don't have to use generics if I don't want to. Fine, but I will still have to read code written by other people who DO use generics! If I can't make sense of their code, I'm adversely affected., whether or not I use generics myself.
    )0

    1( mthornton Reply 3 Apr 5, 2002 12:39 PM:
    This is true. However once you have made the effort to understand generics, code which uses it well will be easier to comprehend than the non generic equivalent. There is a cost, but the pay back is bigger.
    )1

    2( Charles Obler Reply 5:
    I don't think it's a matter of understanding -- it's a matter of parsing. Ever hear of a language called APL? It was so concise, one could write an entire program on a single line. It required a special APL keyboard and key overstrikes. Each function had its own special keyboard symbol.

    I guess we should be glad that Java has descended from C++, and not from APL! C++ is bad enough, but things COULD always be worse! Sure, it is possible to UNDERSTAND C++ system header files, given enough TIME. But who wants to spend the time? The syntax should be such that the details are less conspicuous than the primary constructs.
    )2



    0( CharlesObler Reply 2 Apr 5, 2002 11:40 AM:
    If runtime-anticipation using existing Java constructs does not solve every problem, well, there's still the wrapper approach -- write the bulk of the code for the Object type, then put typesafe wrappers around the class when it comes time to get specific.
    )0

    1( mthornton Reply 3 Apr 5, 2002 12:39 PM::
    Those runtime wrappers often get typos in them which are not detected until run time.

    Eliminating the floating point types from Java would end the main source of misconceptions (judging by traffic on cljp), but no one seriously proposes doing it.
    )1

    2( Charles Obler Reply 5:
    Not even generics will enable the compiler to catch semantic typos. If I type "20", there's no way the compiler can know I really meant "2.0". No, I take that back. No offense intended, but we COULD add a new primitive to Java which holds only values from 1 to 10!
    )2
  • 843793
    843793 Member Posts: 41,732 Green Ribbon
    0( CharlesObler Reply 2 Apr 5, 2002 11:40 AM:
    Well, then, just add a new interface, similar to
    "Comparable" or "Runnable". Call it "Typeable".
    )0

    1( mthornton Reply 3 Apr 5, 2002 12:39 PM:
    How do you describe to the compiler which arguments
    need to be verified? In the case of a Map you would
    need to specify the type for the key as well as that
    for the values. The generics proposal provides a
    language for descibing these rules.
    )1

    2( Charles Obler Reply 5:
    Thanks for your replies and your interest.

    Map could be handled with a two-operand version of
    the setType(), the first operand specifying the key
    type and the second, the value type.

    I think all my proposal really changes is the syntax.
    The new generic code would be LOOK like normal Java.
    . My solution avoids the angle-brackets and looks
    like run-time code -- and might even BE run-time code,
    depending on the compiler option. It's easier to
    understand generics from a run-time perspective,
    because we have that already -- anybody today can
    write a setType() method and their own add() and
    addAll() methods and get the generics effect.

    If there is really no semantic difference between
    angle-brackets and the less conspicuous setType()
    pseudo-method approaches, then the latter is just as
    feasible as the former. If the insolubility of the
    Halting Problem halts the latter approach, then it
    halts the former approach as well.
    )2
    But there is a semantic difference between the two different syntaxes. In the current form of generic Java, you cannot separate the generic part of the type from the non-generic part of the type. In your form, you can:
    List l = new List();
    if (a)
        l.setType(String);
    else
        l.setType(Integer);
    Thinking of generics as run-time code dramatically changes the nature of generics, because you truly cannot tell at compile time what type a reference will have.

    I still fail to see the problem that the new syntax solves. My experience is that syntax is the most trivial aspect of programming to master. And putting all the type information in the same place clearly indicates that the type information is fixed at compile time.
  • 843793
    843793 Member Posts: 41,732 Green Ribbon
    I was actually taught APL at school (using IBM 1130 and 360 machines)!
    You haven't really indicated how the parameters to your setType methods would be associated with the argument and return types of other methods in the class. Also when you pass a collection as a parameter, how do you infer the constraints on the type of its content? The generics proposal allows one to declare that a parameter will be a List<Integer> (i.e. a List that only has Integer objects in it).
    You could write a method like:
    void add(List a) {
    assert a.getElementType() == Integer.class;
    // ...
    }

    Then conceivably the compiler/JIT could treat this assert as equivalent to
    void add(List<Integer> a) {
    // ...
    }

    But I think this is much harder, especially if you want compile time verification.
  • brucechapman
    brucechapman Member Posts: 466
    Maybe I'm slow, but it takes me several minutes of
    staring to figure out what the intent is, in some of
    these examples. The problem is, the syntax introduces
    a whole new level of abstraction. So when I see that
    <T implements X>, I can no longer think "Integer" or
    "StringBuffer" or "JTextArea" -- instead, I have to
    think "X", and all of the things that "X" could ever
    possibly represent. My eyes glaze over, which is
    exactly what happens when I look at C++ code.
    EXACTLY RIGHT. Generics is a whole new level of abstraction. Like you, my eyes also glaze over, but in my case, it is with excitement and wonder at what the future holds.


    When we (exclusive of me, I'm not that old), used to program by toggling switches to represent each bit in a machine code instruction, then push a button to write it into memory - it got people thinking, and they came up with assembler languages.

    Opcodes moved from being inferred, to being explicit.

    Then the people that wrote in assembler languages (I have done some of that), got thinking about loops, and conditions and such like, and how the computer could help them, and so the first high level languages were developed.

    Control statements and data types moved from being inferred to being explicit.

    Then the people that wrote programs in high level languages, got thinking about what they did, and how the computer could help them, and Object Oriented Programming languages were developed.

    Objects moved from being inferred to being explicit.

    Then the people that wrote programs in OO languages got thinking about what they did, and Design patterns were documented, but the pervasive OO languages didn't support them at the language level even though you can use them (just as assembler languages don't support a general purpose while loop, but you can write a while loop in assembler.)

    Then there was the future. (This bring us to the present in this brief history of computing languages)

    The pattern here is that each level initially allows us codify what we are already doing as best practice in the previous level, but in a way that allows us to communicate our intend, both to others who read our code and also to the compiler to check we are doing it correctly.

    Also the features in thenew level then frees our brains from fighting the language constraints of the lower level, so that we can start to think about the way we do our craft. Some of these ways of doing the craft become best practice, Finally these best practices spawn new languages or new language features. The new language features allow us to explicitly codify what we are already doing as best practice, but in a way that allows us to communicate our intend, both to others who read our code and also to the compiler to check we are doing it correctly.

    Does this sound like the start of a never ending story?



    Thus history teaches that by developing languages (or language features) that allow us to codify what we are thinking in the way we think it, rather than merely implementing it, then we can bootstrap ourselves up to the next level of abstraction.

    GENERICS ARE ANOTHER LEVEL OF ABSTRACTION.

    I PREDICT GENERICS WILL ALLOW US TO CODE DESIGN PATTERNS FOR RE-USE.

    (I can say this confidently because I have begun to do it)

    This will make the code intent easier to understand, and lead to more maintainable code.

    When you read a javadoc generated API there will be stuff there that documents the Design patterns and which classes are performing which roles for each instance of the pattern. (I haven't done that yet, because I need a javadoc compiler for Generics !!)

    FURTHER - I PREDICT THAT ONCE WE START CODING THE DESIGN PATTERNS WE ARE USING - WE WILL THEN BE ABLE TO THINK ABOUT THE NEXT HIGHER LEVEL OF ABSTRACTION AFTER THAT.

    (To illustrate, my initial work suggests that a by product of generics is that you can get classes (not interfaces), that must exist in order to allow other classes to compile correctly, but are never executed (or even loaded) at run-time. The implication of this might be that these classes should execute at compile time, rather than runtime. )

    Sure Generics and collections go together nicely, but that is at the level of explicitly coding what was previously inferred. It gives us some compile time checking (I am all for that), and makes our intend more obvious to human readers of our code.

    But the real benefit of generics will come when we find new and novel uses for them.

    There will be situations where generics will allow us to infer something, that previously we could not even think about. In fact, we will probably do it before we realize we are doing it ( c.f. patterns were used before patterns were though about and control. structures were used before control statements were invented).

    We will then start to identify and document these things that are inferred, and start to understand them in an abstract way.

    After some time we will find ways to advance our languages to make these new things explicit in our code, and the cycle will have performed another revoulution.

    And that is why generics makes MY eyes glaze over (with excitement and wonder)

  • 843793
    843793 Member Posts: 41,732 Green Ribbon
    As far as I know, everyone agrees that generics is
    not needed. It's simply helpful in writing
    correct programs.
    This point could be extended to everything above machine code level so you need to redefine "needed" to something more than simply the ability to express a solution in the language; think about the programmer, i.e. the whole point of higher-level languages as well as the number of expressions required to solve a given problem.

  • 843793
    843793 Member Posts: 41,732 Green Ribbon
    "The pattern here is that each level initially allows us codify what we are already doing as best practice in the previous level, but in a way that allows us to communicate our intend, both to others who read our code and also to the compiler to check we are doing it correctly. "

    I think this quote captures it pretty nicely. As well as what was said about design patterns; being able to express design patterns in classes and not just in natural language.

This discussion has been closed.