Click here to load reader
Upload
others
View
2
Download
0
Embed Size (px)
Citation preview
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