News for hackers. Stuff that matters.
Re:Background: how we got the generics we have (2020) by riffraff on Thursday April 01, 2021 @08:01AM (#26659377)
I don't understand what you're saying, what is the problem with L<Integer> ?
Re:Background: how we got the generics we have (2020) by Taig on Thursday April 01, 2021 @08:42AM (#26659739)
The feature that mrkeen is describing is called higher kinded types (HKT). I.e. in Scala (and similarly in Haskell), you could write something like:

    def process[L[_]](input: L[Int]): Unit = ???
Where `L[_]` could be any type that has a type parameter, e.g. `List[_]`, `Option[_]`, `Future[_]` or `Either[String, *]`. This opens the door to a new level of abstraction where other languages must resort to code generation or similar ad hoc-like solutions.
Re:Background: how we got the generics we have (2020) by riffraff on Friday April 02, 2021 @12:34PM (#26672995)
oh, I see thanks for the explanation.
Re:Background: how we got the generics we have (2020) by mrkeen on Thursday April 01, 2021 @08:27AM (#26659566)
There shouldn't be a problem with it!

    <L> void process(final L<Integer> input) {
    }

    ------------------------------------------

    <L> void process(final L<Integer> input) {
                           ^
    required: class
    found:    type parameter L
    where L is a type-variable:
      L extends Object declared in method <L>process(<any>)
Re:Background: how we got the generics we have (2020) by p2t2p on Thursday April 01, 2021 @09:52AM (#26660513)
Works perfectly:

public <T extends Collection<Integer>> T process(T collectionOfInteger) { return collectionOfInteger; }

Re:Background: how we got the generics we have (2020) by willtim on Thursday April 01, 2021 @12:54PM (#26663050)
This uses subtyping polymorphism not higher-kinded parametric polymorphism. If subtyping worked perfectly in all important cases, "generics" (parametric polymorphism) would not have been retrofitted to Java.
Re:Background: how we got the generics we have (2020) by petersellers on Thursday April 01, 2021 @12:53PM (#26663025)
What if your "T" isn't a collection though?
Re:Background: how we got the generics we have (2020) by p2t2p on Thursday April 01, 2021 @09:02PM (#26668149)
Yeah, as Joker_vD said you need _some_ common ground as to where you get your methods from.

I dream about "implicit" interfaces in Java like in Go. So everything that has "flatMap" would implicitly implement "FlatMappable" or something like that.

Re:Background: how we got the generics we have (2020) by Joker_vD on Thursday April 01, 2021 @01:10PM (#26663317)
Then what can you really do with it except of returning it back as-is?
Re:Background: how we got the generics we have (2020) by throw149102 on Saturday April 03, 2021 @01:11AM (#26678576)
Nothing - unless you also take a function that allows you to transform from one type to another. For example, you can write a function like:

  S<U> map(S<B> b, (B -> U) func) { //stuff}
Which allows you to do things like:

  Optional<Integer> i = 4;
  (Integer -> Float) func = (i \* 2.5);
  Optional<Float> f = map(i, func);
This ability becomes much more powerful when you're parsing some file. Imagine you're parsing some JSON of people, and you're using https://schema.org/Person as the type. So the JSON contains things like additionalName, affiliation, birthPlace, email, gender, image, etc. and each of those are typed respectively - a Name class, Affiliation Class, Location class, Email class, Gender class, Image class, etc. Now imagine that the service you're calling may fail to return certain values.

In java, it's idiomatic for libraries like Gson to return null on the fields that aren't returned - so if you try to get a person who doesn't have an additionalName, the additionalName field in the Person object will be null. It would be nice if it could be an Optional<AdditionalName> instead of just an AdditionalName to force the null check, but then the library becomes extremely painful to use. You would end up having to call additionalName.get() whenever you just want the name. If you have HKTs, then you can operate on the fields and ignore the fact that they're technically Optionals.

It's also generally recommended in Java to not use Optionals in fields in classes, or to express the optionality of a value in a constructor. If you do, you have to wrap values in Optionals to make the object, which harms readability.

HKTs can become even more powerful with types other than Optional/Maybe. Either, Monad, Future, Comonad, IO, Functor, Applicative, Task, etc. You would be surprised how many design patterns in Java end up being just a simple combination of these types that are much more ergonomic with HKTs.

Re:Background: how we got the generics we have (2020) by still_grokking on Saturday April 03, 2021 @01:42AM (#26678666)
Indeed, without a type-class constraint on the type constructor this isn't useful at all.

Something like the following Scala 3 code is closer to the actual intend, I think:

  @main def entryPoint =
  
    trait ConsoleLogger[W[_]]:
      extension[E] (w: W[E]) def log(): Unit

    given ConsoleLogger[List] with
      extension[A] (list: List[A]) def log() = println(list)

    given ConsoleLogger[Some] with
      extension[A] (some: Some[A]) def log() = println(some)

    def process[E, L[_] : ConsoleLogger](input: L[E]): Unit =
      input.log()

    process(List(23))
    process(Some("'process' is generic!"))
    //process(None) // Does not compile — even Some and None are interchangeable under subtype polymorphism
Here process(input) can work with any wrapped input as long as a ConsoleLogger instance is given for a specific wrapper type. The point is: There doesn't need to be any relation between the wrapper types (like in the example with List and Option.Some), only the "shape" needs to match W[_] (which could be actually also adapted with type lambdas in case it doesn't match, but not going into this here).