introducing scala-like functional interfaces into javapl/talks/badhonnef_15_slides.pdf ·...

Click here to load reader

Upload: others

Post on 12-Aug-2020

1 views

Category:

Documents


0 download

TRANSCRIPT

  • Introducing Scala-like functional interfaces into Java

    Martin Plümicke

    Baden-Wuerttemberg Cooperative State UniversityStuttgart/Horb

    6. Mai 2015

  • Overview

    Function types in Java-8Functional interfaces as Java target types of lambda expressionsSimulating function types

    Introducing real function typesScala function types

    Function types and type-erasures

    Integration of functional interfaces and function types

    Conclusion and Outlook

  • Lambda–Expressions in Java 8

    (x) -> x;

    has no explicite type.

    Lambda–expressions get functional interfaces as compatible target typesfrom the environment.

  • Lambda–Expressions in Java 8

    (x) -> x;

    has no explicite type.

    Lambda–expressions get functional interfaces as compatible target typesfrom the environment.

  • Functional Interface

    Interfaces with a single abstract method.

    E.g.

    interface Comparator { int compare(T x, T y); }interface FileFilter { boolean accept(File x); }interface DirectoryStream.Filter { boolean accept(T x); }interface Runnable { void run(); }interface ActionListener { void actionPerformed(...); }interface Callable { T call(); }

  • Functional interfaces as compatible target types of lambdaexpressions

    A lambda expression is compatible with a type T , if

    I T is a functional interface type

    I The lambda expression has the same number of parameters as T ’smethod, and those parameters’ types are the same

    I Each expression returned by the lambda body is compatible withT ’s method’s return type

    I Each exception thrown by the lambda body is allowed by T ’smethod’s throws clause

  • Target type (Example)

    Identity id_fun = (x) -> x;

    interface Identity {int id(int x) ;

    }

    Application:

    ...

    System.out.println(id_fun.id(5));

    ...

    Problems:

    I The type’s structure of id fun is not visible.

    I Method’s (id’s) type is not principal.

    I The name of the method id is arbitrary.

  • Simulating function typesCanonical representation

    Lemma: There is an equivalence class of compatible target types for alambda expression. For the equivalence class of the compatible targettypes of a lambda expression, there is a canonical representation

    FunN

    with

    interface FunN

    { R apply(T1 arg1 , ..., TN argN ); }

    if the type of the single method of a compatible target type is

    (T 1, . . . ,T N)→ R

  • Subtyping

    (T ′1, . . . ,T′N)→ T0 ≤∗ (T1, . . . ,TN)→ T ′0, iff Ti ≤∗ T ′i

    FunN 6≤∗ FunN , for Ti �∗ T ′i

    Example:For Integer ≤∗ Number ≤∗ Object holds:

    Number → Number ≤∗ Integer → Object

    but

    Fun1 f NumNum = ...

    Fun1 f IntObj = f NumNum

    is wrong!, as

    Fun1 6≤∗ Fun1

  • Subtyping

    (T ′1, . . . ,T′N)→ T0 ≤∗ (T1, . . . ,TN)→ T ′0, iff Ti ≤∗ T ′i

    FunN 6≤∗ FunN , for Ti �∗ T ′i

    Example:For Integer ≤∗ Number ≤∗ Object holds:

    Number → Number ≤∗ Integer → Object

    but

    Fun1 f NumNum = ...

    Fun1 f IntObj = f NumNum

    is wrong!, as

    Fun1 6≤∗ Fun1

  • Subtyping

    (T ′1, . . . ,T′N)→ T0 ≤∗ (T1, . . . ,TN)→ T ′0, iff Ti ≤∗ T ′i

    FunN 6≤∗ FunN , for Ti �∗ T ′i

    Example:For Integer ≤∗ Number ≤∗ Object holds:

    Number → Number ≤∗ Integer → Object

    but

    Fun1 f NumNum = ...

    Fun1 f IntObj = f NumNum

    is wrong!, as

    Fun1 6≤∗ Fun1

  • Subtyping

    (T ′1, . . . ,T′N)→ T0 ≤∗ (T1, . . . ,TN)→ T ′0, iff Ti ≤∗ T ′i

    FunN 6≤∗ FunN , for Ti �∗ T ′i

    Example:For Integer ≤∗ Number ≤∗ Object holds:

    Number → Number ≤∗ Integer → Object

    but

    Fun1 f NumNum = ...

    Fun1 f IntObj = f NumNum

    is wrong!, as

    Fun1 6≤∗ Fun1

  • Subtyping with wildcards

    (T ′1, . . . ,T′N)→ T0 ≤∗ (T1, . . . ,TN)→ T ′0, iff Ti ≤∗ T ′i

    FunN 6≤∗ FunN , for Ti �∗ T ′i

    but

    FunN

    ≤∗ FunN

  • Subtyping with wildcards

    (T ′1, . . . ,T′N)→ T0 ≤∗ (T1, . . . ,TN)→ T ′0, iff Ti ≤∗ T ′i

    FunN 6≤∗ FunN , for Ti �∗ T ′i

    but

    FunN

    ≤∗ FunN

  • Subtyping with wildcards (Example):

    Example:

    Object m(Integer x, Fun1

  • Subtyping with wildcards (Example):

    Example:

    Object m(Integer x, Fun1

  • Subtyping with wildcards (Example):

    Example:

    Object m(Integer x, Fun1

  • Subtyping with wildcards (Example):

    Example:

    Object m(Integer x, Fun1

  • Syntax of function types with wildcards

    //A -> (B -> (((A, B) -> C) -> C)))

    g = x -> y -> f -> f.apply(x,y);

  • Syntax of function types with wildcards

    //A -> (B -> (((A, B) -> C) -> C)))

    Fun1

  • Syntax of function types with wildcards

    //A -> (B -> (((A, B) -> C) -> C)))

    Fun1

  • Direct application of lambda expressions

    ((x1,..., xN) -> h(x1,..., xN)).apply(arg1....,argN);

    wrong!, as the lambda expression has no type

    ((FunN )((x1,..., xN) -> h(x1,..., xN))).apply(arg1....,argN);

    ok!, as there is cast–expression

    Currying: f : T1 → T2 → . . .→ TN → T0

    ((Fun1 )(x1) -> (x2) ->...-> (xN) -> h(x1,...,XN))

    .apply(a1).apply(a2).....apply(aN)

  • Direct application of lambda expressions

    ((x1,..., xN) -> h(x1,..., xN)).apply(arg1....,argN);

    wrong!, as the lambda expression has no type

    ((FunN )((x1,..., xN) -> h(x1,..., xN))).apply(arg1....,argN);

    ok!, as there is cast–expression

    Currying: f : T1 → T2 → . . .→ TN → T0

    ((Fun1 )(x1) -> (x2) ->...-> (xN) -> h(x1,...,XN))

    .apply(a1).apply(a2).....apply(aN)

  • Direct application of lambda expressions

    ((x1,..., xN) -> h(x1,..., xN)).apply(arg1....,argN);

    wrong!, as the lambda expression has no type

    ((FunN )((x1,..., xN) -> h(x1,..., xN))).apply(arg1....,argN);

    ok!, as there is cast–expression

    Currying: f : T1 → T2 → . . .→ TN → T0

    ((Fun1 )(x1) -> (x2) ->...-> (xN) -> h(x1,...,XN))

    .apply(a1).apply(a2).....apply(aN)

  • Summary Problems:

    I Loss of function types ⇒ Introducing FunN–Interfaces

    I FunN–Subtyping problem ⇒ Using wildcards

    I Impossibility of direct application of lambda expressions⇒ Using type-casts

    All problems are solvable, but not pretty!!!

    ⇒ Introducing real function types

  • Summary Problems:

    I Loss of function types ⇒ Introducing FunN–Interfaces

    I FunN–Subtyping problem ⇒ Using wildcards

    I Impossibility of direct application of lambda expressions⇒ Using type-casts

    All problems are solvable, but not pretty!!!

    ⇒ Introducing real function types

  • Wildcards motivation

    Vector

  • Wildcards motivation

    Vector

  • Comparison to function types

    There is no motivation for bounded wildcards to allow subtyping inparameters!!!

    It holds:

    (T ′1, . . . ,T′N)→ T0 ≤∗ (T1, . . . ,TN)→ T ′0, iff Ti ≤∗ T ′i ,

    which means it should hold:

    FunN ≤∗ FunN , for Ti �∗ T ′i

  • View to Scala

    Scala supports variance annotations of type parameters of genericclasses. In contrast to Java 5 (aka. JDK 1.5), variance annotations maybe added when a class abstraction is defined, whereas in Java 5, varianceannotations are given by clients when a class abstraction is used.[Scala Tutorial]

    trait Function_n[-T1 , ... , -Tn, +R] {def apply(x1: T1 , ..., xn: Tn): R

    override def toString = ""

    }

  • View to Scala

    Scala supports variance annotations of type parameters of genericclasses. In contrast to Java 5 (aka. JDK 1.5), variance annotations maybe added when a class abstraction is defined, whereas in Java 5, varianceannotations are given by clients when a class abstraction is used.[Scala Tutorial]

    trait Function_n[-T1 , ... , -Tn, +R] {def apply(x1: T1 , ..., xn: Tn): R

    override def toString = ""

    }

  • Introduction of FunN*

    interface FunN * {R apply(T1 arg1, ..., TN argN );

    }

    where

    I FunN ∗≤∗ FunN ∗ iff Ti≤∗ T′iI For FunN∗ no wildcards are allowed.

    Proposal: Lambda–expressions are explicitly typed by FunN*–types

  • Introduction of FunN*

    interface FunN * {R apply(T1 arg1, ..., TN argN );

    }

    where

    I FunN ∗≤∗ FunN ∗ iff Ti≤∗ T′iI For FunN∗ no wildcards are allowed.

    Proposal: Lambda–expressions are explicitly typed by FunN*–types

  • Solved Problems

    I Lambda–expressions has types

    I FunN∗–types allows subtyping without wildcardsI Direct application of lambda–expressions is possible without

    type-casts, as lambda–expressions have types.

  • Function types and type-erasuresOverloading example

    void apply(Fun*1 f) { ... }

    void apply(Fun*1 f) { ... }

    Leads in byte-code to (type-erasure):

    void apply(Fun*1 f) { ... }

    void apply(Fun*1 f) { ... }

    Ambigous overloading!

  • Function types and type-erasuresOverloading example

    void apply(Fun*1 f) { ... }

    void apply(Fun*1 f) { ... }

    Leads in byte-code to (type-erasure):

    void apply(Fun*1 f) { ... }

    void apply(Fun*1 f) { ... }

    Ambigous overloading!

  • Translation without Type-Erasures

    I Generic instances in Java Byte Code [Pluemicke 2014, Bad Honnef]

    Approach to solve class loading performance problemI Idea: Instantiated types are subtypes of the non-instantiated type

    [Ureche, Talau, Odersky: Miniboxing: improving the speed to codesize tradeoff in parametric polymorphism translations, OOPSLA,2013]

    I Two Ways to Bake Your Pizza - Translating Parameterised Typesinto Java [Odersky, Runne, Wadler 2000]

    Approach to solve class loading performance problemI changed class loader, that needs only loading a part of the type

    instanced classes.

  • Translation without Type-Erasures

    I Generic instances in Java Byte Code [Pluemicke 2014, Bad Honnef]

    Approach to solve class loading performance problemI Idea: Instantiated types are subtypes of the non-instantiated type

    [Ureche, Talau, Odersky: Miniboxing: improving the speed to codesize tradeoff in parametric polymorphism translations, OOPSLA,2013]

    I Two Ways to Bake Your Pizza - Translating Parameterised Typesinto Java [Odersky, Runne, Wadler 2000]

    Approach to solve class loading performance problemI changed class loader, that needs only loading a part of the type

    instanced classes.

  • Integration Functional Interfaces and FunN∗–Type

    I Java lambda–expressions get FunN∗-Types as explicite types.I Target typing by functional interfaces are preserved.

    I A target type is compatible, if its method’s type is a supertype ofthe FunN∗–type.

  • Brian Goetz’s (Oracle) arguments against real functiontypes

    I It would add complexity to the type system and further mixstructural and nominal types (Java is almost entirely nominallytyped).

    I It would lead to a divergence of library styles – some libraries wouldcontinue to use callback interfaces, while others would use structuralfunction types.

    I The syntax could be unwieldy, especially when checked exceptionswere included.

    I It is unlikely that there would be a runtime representation for eachdistinct function type, meaning developers would be further exposedto and limited by erasure. For example, it would not be possible(perhaps surprisingly) to overload methods m(T->U) and m(X->Y).

  • Brian Goetz’s (Oracle) arguments against real functiontypes

    I It would add complexity to the type system and further mixstructural and nominal types (Java is almost entirely nominallytyped).

    I It would lead to a divergence of library styles – some libraries wouldcontinue to use callback interfaces, while others would use structuralfunction types.

    I The syntax could be unwieldy, especially when checked exceptionswere included.

    I It is unlikely that there would be a runtime representation for eachdistinct function type, meaning developers would be further exposedto and limited by erasure. For example, it would not be possible(perhaps surprisingly) to overload methods m(T->U) and m(X->Y).

  • Brian Goetz’s (Oracle) arguments against real functiontypes

    I It would add complexity to the type system and further mixstructural and nominal types (Java is almost entirely nominallytyped).

    I It would lead to a divergence of library styles – some libraries wouldcontinue to use callback interfaces, while others would use structuralfunction types.

    I The syntax could be unwieldy, especially when checked exceptionswere included.

    I It is unlikely that there would be a runtime representation for eachdistinct function type, meaning developers would be further exposedto and limited by erasure. For example, it would not be possible(perhaps surprisingly) to overload methods m(T->U) and m(X->Y).

  • Brian Goetz’s (Oracle) arguments against real functiontypes

    I It would add complexity to the type system and further mixstructural and nominal types (Java is almost entirely nominallytyped).

    I It would lead to a divergence of library styles – some libraries wouldcontinue to use callback interfaces, while others would use structuralfunction types.

    I The syntax could be unwieldy, especially when checked exceptionswere included.

    I It is unlikely that there would be a runtime representation for eachdistinct function type, meaning developers would be further exposedto and limited by erasure. For example, it would not be possible(perhaps surprisingly) to overload methods m(T->U) and m(X->Y).

  • Conclusion and Outlook

    ConclusionI Problems with functional interfaces as target types of

    lambda–expressions in Java 8.

    I Simulating of function types by functional interfaces FunN.

    I Introduction of Scala-like functional interfaces into Java.

    I Integration of both approaches.

    OutlookI Theoretical foundation

    I Implementation

    I Bytecode without type-erasures

  • Conclusion and Outlook

    ConclusionI Problems with functional interfaces as target types of

    lambda–expressions in Java 8.

    I Simulating of function types by functional interfaces FunN.

    I Introduction of Scala-like functional interfaces into Java.

    I Integration of both approaches.

    OutlookI Theoretical foundation

    I Implementation

    I Bytecode without type-erasures

  • Stellenausschreibung

    DHBW (M. Plümicke) gemeinsam mit der Uni Freiburg (P. Thiemann)

    Wissenschaftlicher Mitarbeiter/in

    Promotionsthema: Real function types in Java

    Bei Interesse: Martin Plümicke, [email protected], 07451-521142

    Function types in Java-8Functional interfaces as Java target types of lambda expressionsSimulating function types

    Introducing real function typesScala function types

    Function types and type-erasuresIntegration of functional interfaces and function typesConclusion and Outlook