8

As stated by this blog, we are now able to write the following using local type inference (something, to my knowledge, that was previously impossible without introducing more code):

public static void main(String... args) {
    var duck = (Quacks & Waddles) Mixin::create;
    duck.quack();
    duck.waddle();
}

interface Quacks extends Mixin {
    default void quack() {
        System.out.println("Quack");
    }
}

interface Waddles extends Mixin {
    default void waddle() {
        System.out.println("Waddle");
    }
}

interface Mixin {
    void __noop__();
    static void create() {}
}

This question may be either too broad or primarily opinion-based, but do there exist any useful applications when taking advantage of intersection types like this?

Naman
  • 27,789
  • 26
  • 218
  • 353
Jacob G.
  • 28,856
  • 5
  • 62
  • 116
  • Am I getting you wrong, is this question about the usefulness of `var` OR *intersection types*? I guess either me or Eugene, please try to improve the tag for the same, it doesn't need java-10 tag for the latter. – Naman Mar 21 '18 at 16:13
  • @nullpointer I was just about to comment, but this question is mostly aimed at the usefulness of intersection types now that we can use `var` to create them (somewhat). – Jacob G. Mar 21 '18 at 16:14
  • `var` is not a way(only) to create them, you could have done that prior to `var` (java-10) as well. I really think this should be aimed at finding the usefulness of intersection types in that case. – Naman Mar 21 '18 at 16:19
  • @nullpointer *Create* was a poor choice on my part; I think *represent* fits better. And yes, that's what I was aiming for. Eugene's link helps, but I'm curious as to what applications can come from this. – Jacob G. Mar 21 '18 at 16:21

2 Answers2

7

Dealing with partially unknown types is possible since Java 5, so it’s quite easy to backport your example to Java 8:

public static void main(String... args) {
    use((Quacks & Waddles)Mixin::create);
}
private static <Duck extends Quacks & Waddles> void use(Duck duck) {
    duck.quack();
    duck.waddle();
}
interface Quacks extends Mixin {
    default void quack() {
        System.out.println("Quack");
    }
}
interface Waddles extends Mixin {
    default void waddle() {
        System.out.println("Waddle");
    }
}
interface Mixin {
    void __noop__();
    static void create() {}
}

So the possibility to do the same using var in Java 10 allows, well, to do the same as before, but with slightly less source code. And being able to do the same things as before but with less boilerplate code is exactly what var is about, whether you use intersection types or not.

Holger
  • 285,553
  • 42
  • 434
  • 765
4

You can sort of do that in java-8 too:

static class ICanDoBoth implements Quacks, Waddles {
    // implement void __noop__(); here...
}

public static void both(Object b) {
    // my point here is that you can't declare such a type 'x'
    Optional.of((Quacks & Waddles) b)
            .ifPresent(x -> {
                x.quack();
                x.waddle();
            });
}

And call it via: both(new ICanDoBoth());

Thing is you can't declare a variable of an intersection type (well, unless var or a variable that is inferred by the compiler with Optional.of()).

Practically there are some hints here, but I've never used a variable of a intersection type in something very useful...

Eugene
  • 117,005
  • 15
  • 201
  • 306
  • 2
    You don’t need the `ICanDoBoth` interface in Java 8, you can use method references with intersection types the same way as in the question. Doing the same as in the question takes only two additional lines of code… – Holger Mar 22 '18 at 11:34
  • @Holger a year after I came to understand this comment. but casting a method reference to an intersection type... oh boy. – Eugene Mar 06 '19 at 21:34