This week's book giveaway is in the Kotlin forum.
We're giving away four copies of Kotlin Cookbook and have Ken Kousen on-line!
See this thread for details.
Win a copy of Kotlin Cookbook this week in the Kotlin forum!
  • 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 all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Liutauras Vilda
  • Bear Bibeault
  • Paul Clapham
  • Jeanne Boyarsky
Sheriffs:
  • Junilu Lacar
  • Knute Snortum
  • Henry Wong
Saloon Keepers:
  • Ron McLeod
  • Tim Moores
  • Stephan van Hulst
  • Tim Holloway
  • Carey Brown
Bartenders:
  • Frits Walraven
  • Joe Ess
  • salvin francis

Generics, Understanding Complex Expressions. Are they necessary to understand ?

 
Greenhorn
Posts: 11
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator


I'm trying to understand some complex generics expressions. For example, what does the expression above mean?
 
Saloon Keeper
Posts: 11018
243
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
These are not expressions but declarations. Expressions are parts of a statement that return a value. In programming, it's important to use the correct terminology.

First you declare an interface Foo with a generic type parameter T. We say "Foo of T".

Secondly you declare a class FooImpl with a generic type parameter U. U has an upper type boundary of Foo<? super U>. We say "FooImpl of U, where U is some subtype of a Foo that consumes U".

You are probably wondering about the "U is some subclass of a Foo that consumes U" part. I will be able to explain it a bit better using types that have more meaning than Foo and FooImpl:

SortedSequence maintains a sorted list of items. You can insert a new item and it will perform a binary search on the current list of items to find the index where the item will be inserted.

To make all of this work, the items need to be comparable to each other. That's why U extends Comparable. However, Comparable is also a generic type, so we need to specify type arguments: U extends Comparable<U> because the items need to be comparable to themselves.

So why does the actual declaration read U extends Comparable<? super U> ? That's because otherwise we'd be needlessly limiting the type of things we can make a sorted sequence of. Here's an example:

Why is it not possible to create a sequence of sheep, even though Sheep extends Animal and Animal is comparable to itself? Well, SortedSequence requires something that extends Comparable<Sheep>, and Sheep is not a Comparable<Sheep> but a Comparable<Animal>.

When instead we declare U as U extends Comparable<? super U>, we CAN create a SortedSequence<Sheep>, because the SortedSequence requires something that extends Comparable<? super Sheep>, and Comparable<Animal> does just that.

Finally, why do we say "consumes" in "SortedSequence of U, where U is some subtype of a Comparable that consumes U"? Well, the super keyword is used to specify a lower type bound on types that contain methods that only have the generic type in their method parameters, not in their return values. Comparable has T as a parameter in its compareTo method, and not in its return type. That's why we can use the super keyword, and that's why we say "Comparable that consumes U".
 
That is a really big piece of pie for such a tiny ad:
Sauce Labs - World's Largest Continuous Testing Cloud for Websites and Mobile Apps
https://coderanch.com/t/722574/Sauce-Labs-World-Largest-Continuous
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
Boost this thread!