• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Jeanne Boyarsky
  • Ron McLeod
  • Paul Clapham
  • Liutauras Vilda
Sheriffs:
  • paul wheaton
  • Rob Spoor
  • Devaka Cooray
Saloon Keepers:
  • Stephan van Hulst
  • Tim Holloway
  • Carey Brown
  • Frits Walraven
  • Tim Moores
Bartenders:
  • Mikalai Zaikin

The super keyword - everything is everything?

 
Ranch Hand
Posts: 353
3
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I see the super keyword in different contexts.  Is it the case of "when I use a word, it means what I say it means"?








I have, so far, not encountered any class where super or super() is listed as a member of the class.  So, is super a hidden member of every subclass?
 
Saloon Keeper
Posts: 15510
363
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Biniman Idugboe wrote:


No. There is no separate instance of the superclass. There is only one instance, and that instance has multiple types. In this context, the super keyword refers to the current instance (like this does), but instead of using the method implementation given by the class that the super keyword appears in, it uses the method implementation given by the direct superclass.


It's just like the first case, except it's a method handle.


Yes.


Yeah, but that's not the entire story, is it? In this case,  the super keyword is used to declare a type bound for a generic type parameter. It means that whatever type parameter or wildcard comes before the keyword has a restriction that it must hold a supertype of T. This has nothing to do with the other uses of super. The just used the same keyword for an unrelated concept.


Nothing. This is not valid Java code.

So, is super a hidden member of every subclass?


Not really. It's a keyword. That means it's special and Java treats it specially. But if it makes life easier for you then you can think of it as a hidden method parameter (but it's not!).
 
Biniman Idugboe
Ranch Hand
Posts: 353
3
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
super<?, T> is not valid. I am not surprised.  I made it up and I thought it might just be another form of super.


T super T means a range of classes from S to T.  Please, confirm!
 
Biniman Idugboe
Ranch Hand
Posts: 353
3
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Actually, I do not know what you meant by saying that one instance has multiple types.
 
Stephan van Hulst
Saloon Keeper
Posts: 15510
363
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

This is also not valid code. The thing before the super keyword must be a type parameter or a wildcard, and T is not a type parameter but a type.

Biniman Idugboe wrote:Actually, I do not know what you meant by saying that one instance has multiple types.


Well, in the code you just posted, if you create an instance of T, that instance will be of type T, but it will also be of type S, and it will also be of type Object.
 
Marshal
Posts: 79178
377
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Biniman Idugboe wrote:. . . one instance has multiple types.

Look at a class like this one. At the top of its documentation, it tells you that it is a subclass of Object, so it is an Object. It is also an instance of each of the interfaces it implements, so it is a Serializable, a Comparable, etc.
 
Biniman Idugboe
Ranch Hand
Posts: 353
3
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator


If ? is replaced with class Child, then the super type of Child is Father. So, it would be safe to use this comparator to compare instances of Father or instances of Child.  However, if ? is replaced with Father, the super class of Father would be Object.  In this case, the Child class does not belong to the range of classes covered by the type-safety.  Right?  

So, what exactly is a type parameter?
 
Biniman Idugboe
Ranch Hand
Posts: 353
3
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Correction:
 
Stephan van Hulst
Saloon Keeper
Posts: 15510
363
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
You can't replace the ? by Child or Father, because Child and Father are classes, and at the left of the super keyword there must be a wildcard or type parameter. You also haven't declared T anywhere, so we don't know what it is.

A type parameter is like a variable, except it holds a type instead of a value. You declare type parameters next to the name of a type when you declare the type, or before the return type when you declare a method. Let's take Comparator as an example. It looks like this:

T is a type parameter that holds a type during compilation. You pass a type argument when you declare a variable of type Comparator:

You typically use the super keyword when you write a method or constructor that accepts a consumer. Comparator is an example of a consumer, because it consumes instances of the type argument, for example, stringComparator consumes Strings.

Take a look at List.sort():

It means that to sort the list, it needs to know how to compare two instances of E to each other. It doesn't matter if it gets a comparator of exactly E, or a comparator of a supertype of E.
 
Biniman Idugboe
Ranch Hand
Posts: 353
3
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Thanks for the clarifications Stephan. Perhaps, I should have said replace ? super T with Child or with Father at the time of implementing the Comparator.
 
Biniman Idugboe
Ranch Hand
Posts: 353
3
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

So, this comparator can be used to compare instances of any class.  All the programmer needs to do is replace the type parameter T with a real class at the time of implementation.


The type parameter is now not a single parameter.  How many parameters are there?
 
Stephan van Hulst
Saloon Keeper
Posts: 15510
363
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
What do you mean by the type parameter is not a single parameter? T is T.
 
Biniman Idugboe
Ranch Hand
Posts: 353
3
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Is ? super T a single parameter?
 
Campbell Ritchie
Marshal
Posts: 79178
377
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Yes. It means any supertype of T, but for the purposes of generics, T is included as being a supertype of itself.
The correct formal type parameter for Comparable is ...<T extends Comparable<? super T>>, which is itself a single parameter.
 
Biniman Idugboe
Ranch Hand
Posts: 353
3
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
The API says
@FunctionalInterface

Therefore, I can do Comparator<String> comp = ....
So, what exactly are we trying to achieve by saying Comparator<? super T> ?  
Is Comparator<? super T> extending Comparator<T> ?
 
Bartender
Posts: 10780
71
Hibernate Eclipse IDE Ubuntu
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Biniman Idugboe wrote:Is ? super T a single parameter?


Yup, and don't worry; it IS confusing.

The problem is that generics is a bolt-on to Java, not a native part of the language; and when it was implemented:
1. It had to be backwards-compatible with all existing code.
2. No existing code had any concept of a 'type'.

I think they did a pretty good job in the circumstances, but lots of constructs (like Campbell's example above) just look "messy" - even after ... what is it now? ... 10 years?

Winston
 
Stephan van Hulst
Saloon Keeper
Posts: 15510
363
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
No, "? super T" is a type argument, not a type parameter. It's the value that you pass to the type parameter T declared inside the Comparator class and it uses, confusingly, the value that is currently stored in a different type parameter that is also called T that was declared in whatever class you have written that code snippet in. Maybe it's easier for you to understand if we consider a language I just made up that looks like Java, but type parameters work the same way as regular fields and method parameters do:

As you can see, type parameters act very much like regular variables in that you can assign values to them and retrieve values from them. When you declare a List<Orange>, you use the 'value' Orange and you assign it to List's type parameter E. Then in List.sort(Comparator<? super E> c), the value of the type parameter E is retrieved (which is currently Orange) and the super operator is applied to it with the wildcard to yield a new value 'something that is a supertype of Orange', and that value is then assigned to the type parameter T of the Comparator.

This means that if you have a List<Orange>, the comparator that you pass to the sort method must be a Comparator<something that is a supertype of Orange>. For instance, you could pass a Comparator<Fruit>. Here, Fruit is a type argument passed to the type parameter T of Comparator.
 
Campbell Ritchie
Marshal
Posts: 79178
377
  • Likes 1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
You write a methodYou can't simply write <Comparable> otherwise you could write foo("123", 456) which is comparing Strings and (boxed) Integers, and that won't work.
You can't simply write <T> otherwise you could pass something like two JFrames, which aren't Comparable at all.
The way to get the same type for both is to write <T extends Comparable>, but even that isn't right because Comparable is itself parameterised, so you have to add the parameter.
<T extends Comparable<T>> mightn't work; you don't know whether T itself implements Comparable<T> or whether one of its supertypes does. So you have to use a wildcard: <T extends Comparable<? super T>>.
 
Stephan van Hulst
Saloon Keeper
Posts: 15510
363
  • Likes 1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Winston Gutkowski wrote:I think they did a pretty good job in the circumstances, but lots of constructs (like Campbell's example above) just look "messy" - even after ... what is it now? ... 10 years?


This is not a consequence of generics in Java being bolted on though. It's because Java has "use site generics". In a language like C#, which also had generics bolted on after the fact, it would look like this, because C# has "declaration site generics":

As you can see, this looks less messy, but that's only because type bounds are fixed in the type definition, whereas Java allows the programmer to set the type bounds when you declare a variable of a generic type.

The main problem of generics not being part of the language from the start is type erasure. Java doesn't keep any type arguments at runtime. In .NET they did it the other way around: they just added a complete new family of generic classes and kept the old non-generic versions of them for backwards compatibility.
 
Stephan van Hulst
Saloon Keeper
Posts: 15510
363
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Campbell Ritchie wrote:<T extends Comparable<T>> mightn't work; you don't know whether T itself implements Comparable<T> or whether one of its supertypes does.


Not true. <T extends Comparable<T>> would work just fine. The reason we use the wildcard is because it is less restrictive. That way, you can pass a Comparable<Fruit> even though T is an Orange.
 
Campbell Ritchie
Marshal
Posts: 79178
377
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Thank you
 
Biniman Idugboe
Ranch Hand
Posts: 353
3
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Stephan

This means that if you have a List<Orange>, the comparator that you pass to the sort method must be a Comparator<something that is a supertype of Orange>. For instance, you could pass a Comparator<Fruit>. Here, Fruit is a type argument passed to the type parameter T of Comparator.


No offence. I have been struggling to understand the concept and syntax and I have simply decided to adopt a roundabout interpretation.
I want to sort List<T> using Comparator<? super T>
I take "? super T" to mean "exactly T or the superclass of T" where T is determined by the class of elements the comparator is going to compare.
So, I can sort List<T> using Comparator<T> or I can sort List<T> using Comparator<super T>

Now, I wish to sort a list containing instances of real class.
I can think of several scenarios as shown below:
1.  Sort List<Apple> using Comparator<Apple>// Correct because Apple class is exactly Apple class.
2.  Sort List<Apple> using Comparator<Fruit>  //Correct! Although Fruit class is not exactly Apple class, the Fruit class is a superclass of Apple class.
3.  Sort List<Fruit> using Comparator<Apple>  // Wrong because Apple class is not exactly Fruit class neither is Apple class a super class of Fruit class.
4.  Sort List<Fruit> using Comparator<Fruit> // Correct because Fruit class is exactly Fruit class.
Anybody sees where this can go wrong?
Seriously, why is it not sufficient to just sort List<T> using Comparator<T> ?  
 
Stephan van Hulst
Saloon Keeper
Posts: 15510
363
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Yes, that's correct.

List.sort() accepts a Comparator<? super T> and not a Comparator<T>, because if it just so happens that I have a Comparator<Fruit> which sorts fruits by sweetness and I have a List<Strawberry>, then why shouldn't I be allowed to sort the strawberries with the comparator I already have?
 
Winston Gutkowski
Bartender
Posts: 10780
71
Hibernate Eclipse IDE Ubuntu
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Stephan van Hulst wrote:List.sort() accepts a Comparator<? super T> and not a Comparator<T>, because if it just so happens that I have a Comparator<Fruit> which sorts fruits by sweetness and I have a List<Strawberry>, then why shouldn't I be allowed to sort the strawberries with the comparator I already have?


I still say it's clumsy. A Comparator should take a Comparable, and very possibly a directed subtype.
To me, the "? super" business is confusing nonsense, and furthermore mechanical nonsense. The first thing you learn about supertypes and interfaces is that they are inherited by ALL subtypes, so why do I have to specify anything other than Comparable unless I want to be more specific??

I love Java, but it sounds like generics syntax is a mechanical issue, and maybe C# got it right (or 'righter').
I also wonder if it might be worth another look now that even standard Java APIs are becoming more complex (how many methods do Comparable/Comparator have now?).

I guess it's 4ยข now. :-)

Winston
 
Bartender
Posts: 5465
212
  • Likes 1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Generics are just a matter of getting used to, like so many things in Java. And the current Comparator is a joy to use, compared to the old Comparator. I often define some more complex compareTo methods in terms of the much more flexible Comparator.
 
Stephan van Hulst
Saloon Keeper
Posts: 15510
363
  • Likes 1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Winston Gutkowski wrote:To me, the "? super" business is confusing nonsense, and furthermore mechanical nonsense. The first thing you learn about supertypes and interfaces is that they are inherited by ALL subtypes


You're talking about covariance which is the exact opposite of what a comparator needs to do.

C# says that ALL comparators (which are consumers) are contravariant. That means that if you have an IComparer<SuperType> it can always be used where an IComparer<SubType> is expected. For comparators, this is correct because there is probably no situation in which you want a comparator to be covariant or invariant. Conversely, you want all producers to be covariant. For instance, in Java there is no reason you would ever want to declare a method that takes a Supplier<Something> or a Supplier<? super Something>, you will ALWAYS want to declare them as Supplier<? extends Something>. C# also does this nicely by making the Func<TResult> type (which is a producer) inherently covariant.

Like I said before though, C# comes with its own set of problems. Because C# has 'declaration site variance', an interface like IList is ALWAYS invariant. That means there is no way for you to write a method that takes a IList<Lion> and adds lions to the list, and pass that method an List<Animal>. There's also no way for you to write a method that takes an IList<Animal> and takes animals out of the list, and pass that method a List<Lion>. In Java, you can do both!

In C#, I would either have to make the populateWithLions() method accept an IList<Animal>, which means I can no longer pass it an IList<Lion> if I had one, or I need to pass it an IList<Lion> first which I then convert to an IList<Animal> before I can call the printAnimalNames() method. Both options suck.

I love Java, but it sounds like generics syntax is a mechanical issue, and maybe C# got it right (or 'righter').


It's not about syntax. It's an inherent problem rooted in Set Theory. In this regard, Java is verbose but flexible. C# is less wordy, but also gives the programmer fewer options.

Maybe a nice approach would be to allow both declaration site variance and use site variance. For instance, you could specify that Comparator is ALWAYS contravariant, while for a List you would specify whether the list is co-, contra- or invariant when you declare a variable. I don't know what other issues this would result in. I'd have to write a compiler to find out.
 
With a little knowledge, a cast iron skillet is non-stick and lasts a lifetime.
reply
    Bookmark Topic Watch Topic
  • New Topic