concepts of object-oriented programming · 2017. 10. 22. · peter müller –concepts of...
TRANSCRIPT
Concepts of
Object-Oriented Programming
Peter Müller
Chair of Programming Methodology
Autumn Semester 2017
2
Highly
Dynamic
Execution Model
Highly
Dynamic
Execution Model
Active objects
Message passing
Classification and
Specialization
Correctness
Interfaces
Encapsulation
Simple, powerful concepts
Cooperating Program Parts
with Well-Defined Interfaces
Cooperating Program Parts
with Well-Defined Interfaces
Objects (data + code)
Interfaces
Encapsulation
1.2 Introduction – Core Concepts
Meeting the Requirements
Classification, subtyping
Polymorphism
Substitution principle
Peter Müller – Concepts of Object-Oriented Programming
3
Topics in this Section
▪ Cooperating program parts …
- How do we define components?
▪ … with well-defined interfaces
- What is the interface of a component?
- How do we describe the interface of a
component?
- How do we make sure clients use a
component correctly?
Peter Müller – Concepts of Object-Oriented Programming
Types
and
contracts
4. Types
4
Peter Müller – Concepts of Object-Oriented Programming
4. Types
4.1 Bytecode Verification
4.2 Parametric Polymorphism
4. Types
5
Mobile Code: Motivation
▪ Download and execution of code, e.g., Java applets
- Web pages
- Mobile devices
▪ Upload of code
- Customizing servers
▪ Automatic distribution of code and patches in
distributed systems
Peter Müller – Concepts of Object-Oriented Programming
4.1 Types – Bytecode Verification
6
Peter Müller – Concepts of Object-Oriented Programming
Class Loaders
▪ Programs are compiled to bytecode- Platform-independent format
- Organized into class files
▪ Bytecode is interpreted on a virtual machine
Class files
Java Virtual
Machine
Operating System
Class
Loader
Class files
▪ Class loader gets
code for classes
and interfaces on
demand
▪ Programs can
contain their own
class loaders
4.1 Types – Bytecode Verification
7
Peter Müller – Concepts of Object-Oriented Programming
Example: Specialized Class Loader
public class MyLoader extends ClassLoader {
byte[ ] getClassData( String name ) { … }
public synchronized Class loadClass( String name ) throws ClassNotFoundException {
Class c = findLoadedClass( name );
if ( c != null ) return c;
try { c = findSystemClass( name ); return c; }
catch ( ClassNotFoundException e ) { }
byte[ ] data = getClassData( name );
return defineClass( name, data, 0, data.length ); }
}
Error handling partly omitted
4.1 Types – Bytecode Verification
Java
8
Peter Müller – Concepts of Object-Oriented Programming
Security for Java Programs
▪ Sandbox
- Applets get access to
system resources only
through an API
- Access control can be
implemented
▪ Security relies on
- Type safety
- Code does not by-pass
sandbox
4.1 Types – Bytecode Verification
Program
Operating System
API
X
9
Peter Müller – Concepts of Object-Oriented Programming
Security in Mobile Environments
▪ Mobile code cannot be trusted
- Code may not be type safe
- Code may destroy or modify data
- Code may expose personal information
- Code may crash the underlying VM
- Code may purposefully degrade performance (denial of
service)
▪ How to guarantee a minimum level of security?
- Untrusted code producer
- Untrusted compiler
4.1 Types – Bytecode Verification
10
Peter Müller – Concepts of Object-Oriented Programming
Java Virtual Machine
▪ JVM is stack-based
▪ Most operations pop
operands from a stack
and push a result
▪ Registers store
method parameters
and local variables
▪ Stack and registers
are part of the method
activation record
4.1 Types – Bytecode Verification
this
Stack:
R:
Heap:
this p1 l1
obj1
Peter Müller – Concepts of Object-Oriented Programming
Java Bytecode
▪ Instructions are typed
▪ Load and store
instructions access
registers
▪ Control is handled by
intra-method branches
(goto, conditional
branches)
4.1 Types – Bytecode Verification
class C {
void m( ) {
int v;
Object w;
v = 5;
w = this;
}
}
iconst 5
istore 1
aload 0
astore 2
return
this
S: R:
Heap:
this v w
11
Peter Müller – Concepts of Object-Oriented Programming
Java Bytecode
▪ Instructions are typed
▪ Load and store
instructions access
registers
▪ Control is handled by
intra-method branches
(goto, conditional
branches)
4.1 Types – Bytecode Verification
class C {
void m( ) {
int v;
Object w;
v = 5;
w = this;
}
}
iconst 5
istore 1
aload 0
astore 2
return
this
S: R:
Heap:
this v w
5
11
Peter Müller – Concepts of Object-Oriented Programming
Java Bytecode
▪ Instructions are typed
▪ Load and store
instructions access
registers
▪ Control is handled by
intra-method branches
(goto, conditional
branches)
4.1 Types – Bytecode Verification
class C {
void m( ) {
int v;
Object w;
v = 5;
w = this;
}
}
iconst 5
istore 1
aload 0
astore 2
return
this
S: R:
Heap:
this v w
5
11
Peter Müller – Concepts of Object-Oriented Programming
Java Bytecode
▪ Instructions are typed
▪ Load and store
instructions access
registers
▪ Control is handled by
intra-method branches
(goto, conditional
branches)
4.1 Types – Bytecode Verification
class C {
void m( ) {
int v;
Object w;
v = 5;
w = this;
}
}
iconst 5
istore 1
aload 0
astore 2
return
this
S: R:
Heap:
this v w
5
11
Peter Müller – Concepts of Object-Oriented Programming
Java Bytecode
▪ Instructions are typed
▪ Load and store
instructions access
registers
▪ Control is handled by
intra-method branches
(goto, conditional
branches)
4.1 Types – Bytecode Verification
class C {
void m( ) {
int v;
Object w;
v = 5;
w = this;
}
}
iconst 5
istore 1
aload 0
astore 2
return
this
S: R:
Heap:
this v w
5
11
Peter Müller – Concepts of Object-Oriented Programming
Java Bytecode
▪ Instructions are typed
▪ Load and store
instructions access
registers
▪ Control is handled by
intra-method branches
(goto, conditional
branches)
4.1 Types – Bytecode Verification
class C {
void m( ) {
int v;
Object w;
v = 5;
w = this;
}
}
iconst 5
istore 1
aload 0
astore 2
return
this
S: R:
Heap:
this v w
5
11
12
Peter Müller – Concepts of Object-Oriented Programming
Bytecode Verification
▪ Proper execution requires that
- Each instruction is type correct
- Only initialized variables are read
- No stack over- or underflow occurs
- Etc.
▪ Java Virtual Machine guarantees these properties
- By bytecode verification when a class is loaded
- By dynamic checks at run time
4.1 Types – Bytecode Verification
13
Peter Müller – Concepts of Object-Oriented Programming
Bytecode Verification via Type Inference
▪ The Bytecode verifier simulates the execution of the program
▪ Operations are performed on types instead of values
▪ For each instruction, a rule describes how the operand stack and local variables are modified
▪ Errors are denoted by the absence of a transition- Type mismatch
- Stack over- or underflow
4.1 Types – Bytecode Verification
i: ( S,R ) ( S’,R’ )
iadd: ( int.int.S,R ) ( int.S,R )
14
Peter Müller – Concepts of Object-Oriented Programming
Types of the Inference Engine
▪ Primitive types
▪ Object and array reference types
▪ null type for the null reference
▪ T for uninitialized registers
4.1 Types – Bytecode Verification
T
C Object[ ]
null
int floatObject
float[ ]int[ ]
C[ ]
15
Peter Müller – Concepts of Object-Oriented Programming
Selected Rules
▪ Maximum stack
size (MS) and
maximum number
of parameters and
local variables
(MR) are stored in
the classfile
▪ Rule for method
invocation uses
method signature
(no jump)
4.1 Types – Bytecode Verification
iconst n:
( S,R ) ( int.S,R ), if S < MS
iload n:
( S,R ) ( int.S,R ), if 0 n < MR R( n ) = int S < MS
astore n:
( t.S,R ) ( S,R{ n t } ), if 0 n < MR t <: Object
invokevirtual C.m.:( t’n…t’1.t’.S,R ) ( r.S,R ), if = r ( t1,…,tn ) t’ <: C t’i <: ti
16
Peter Müller – Concepts of Object-Oriented Programming
Example
4.1 Types – Bytecode Verification
( [ ] , [ C,T,T ] )
( int , [ C,T,T ] )
( [ ] , [ C,int,T ] )
( C , [ C,int,T ] )
( [ ] , [ C,int,C ] )
iconst 5
istore 1
aload 0
astore 2
return
int v;
Object w;
v = 5;
w = this;
iconst 5
istore 1
iload 1
astore 2
return
int v;
Object w;
v = 5;
w = v;
( [ ] , [ C,T,T ] )
( int , [ C,T,T ] )
( [ ] , [ C,int,T ] )
( int , [ C,int,T ] )
stuck
this v w
astore
expects an
object type
on top of
the stack!
17
Peter Müller – Concepts of Object-Oriented Programming
Smallest Common Supertype
▪ Branches lead to joins
in control flow
▪ Instructions can have
several predecessors
▪ Smallest common
supertype is selected
(T if no other common
supertype exists)
4.1 Types – Bytecode Verification
0: aload 0
1: astore 2
2: aload 1
3: goto 1
0: aload 0 2: aload 1
3: goto 1
1: astore 2
C
ED
( E.S,R )
( C.S,R )
( D.S,R )
18
Peter Müller – Concepts of Object-Oriented Programming
Handling Multiple Subtyping
▪ With multiple subtyping, several smallest common supertypes may exist
▪ JVM solution- Ignore interfaces
- Treat all interface types as Object
- Works because of single inheritance of classes
▪ Problem- invokeinterface I.m cannot check
whether target object implements I
- Run-time check is necessary
4.1 Types – Bytecode Verification
Object
JI
ED
19
Peter Müller – Concepts of Object-Oriented Programming
Inference Algorithm
▪ Inference is a fixpoint iteration
4.1 Types – Bytecode Verification
in( 0 ) := ( [ ] , [ P0,…,Pn,T,…,T ] )
worklist := { i instri is an instruction of the method }
while worklist do
i := min( worklist )
remove i from worklist
out( i ) := apply_rule( instri, in( i ) )
foreach q in successors( i ) do
in( q ) := pointwise_scs( in( q ), out( i ) )
if in( q ) has changed then worklist := worklist { q }
end
end
20
Peter Müller – Concepts of Object-Oriented Programming
Pointwise SCS
▪ scs( s,t ) is the smallest common supertype of s
and t
▪ pointwise_scs is undefined for stacks of different
heights
- Bytecode verification results in an error
4.1 Types – Bytecode Verification
pointwise_scs( ( [ s1…..sk ] , [ t0,…,tn ] ) ,
( [ s’1…..s’k ] , [ t’0,…,t’n ] ) ) =
( [ scs( s1,s’1 )…..scs( sk,s’k ) ] , [ scs( t0,t’0 ),…,scs( tn,t’n ) ] )
Peter Müller – Concepts of Object-Oriented Programming
Inference Example
4.1 Types – Bytecode Verification
0: aload 0
1: astore 2
2: aload 1
3: goto 1
in out
C
ED
worklist
0 1 2 3
( [ ] , [ D,E,T ] )0:
2:
1:
3:
21
Peter Müller – Concepts of Object-Oriented Programming
Inference Example
4.1 Types – Bytecode Verification
0: aload 0
1: astore 2
2: aload 1
3: goto 1
in out
C
ED
worklist
1 2 3
( [ ] , [ D,E,T ] )0:
2:
1:
3:
21
Peter Müller – Concepts of Object-Oriented Programming
Inference Example
4.1 Types – Bytecode Verification
0: aload 0
1: astore 2
2: aload 1
3: goto 1
in out
C
ED
worklist
1 2 3
( [ ] , [ D,E,T ] ) ( [ D ] , [ D,E,T ] )0:
2:
1:
3:
21
Peter Müller – Concepts of Object-Oriented Programming
Inference Example
4.1 Types – Bytecode Verification
0: aload 0
1: astore 2
2: aload 1
3: goto 1
in out
C
ED
worklist
1 2 3
( [ ] , [ D,E,T ] )
( [ D ] , [ D,E,T ] )
( [ D ] , [ D,E,T ] )0:
2:
1:
3:
21
Peter Müller – Concepts of Object-Oriented Programming
Inference Example
4.1 Types – Bytecode Verification
0: aload 0
1: astore 2
2: aload 1
3: goto 1
in out
C
ED
worklist
2 3
( [ ] , [ D,E,T ] )
( [ D ] , [ D,E,T ] )
( [ D ] , [ D,E,T ] )0:
2:
1:
3:
21
Peter Müller – Concepts of Object-Oriented Programming
Inference Example
4.1 Types – Bytecode Verification
0: aload 0
1: astore 2
2: aload 1
3: goto 1
in out
C
ED
worklist
2 3
( [ ] , [ D,E,T ] )
( [ D ] , [ D,E,T ] )
( [ D ] , [ D,E,T ] )
( [ ] , [ D,E,D ] )
0:
2:
1:
3:
21
Peter Müller – Concepts of Object-Oriented Programming
Inference Example
4.1 Types – Bytecode Verification
0: aload 0
1: astore 2
2: aload 1
3: goto 1
in out
C
ED
worklist
2 3
( [ ] , [ D,E,T ] )
( [ D ] , [ D,E,T ] )
( [ ] , [ D,E,D ] )
( [ D ] , [ D,E,T ] )
( [ ] , [ D,E,D ] )
0:
2:
1:
3:
21
Peter Müller – Concepts of Object-Oriented Programming
Inference Example
4.1 Types – Bytecode Verification
0: aload 0
1: astore 2
2: aload 1
3: goto 1
in out
C
ED
worklist
3
( [ ] , [ D,E,T ] )
( [ D ] , [ D,E,T ] )
( [ ] , [ D,E,D ] )
( [ D ] , [ D,E,T ] )
( [ ] , [ D,E,D ] )
0:
2:
1:
3:
21
Peter Müller – Concepts of Object-Oriented Programming
Inference Example
4.1 Types – Bytecode Verification
0: aload 0
1: astore 2
2: aload 1
3: goto 1
in out
C
ED
worklist
3
( [ ] , [ D,E,T ] )
( [ D ] , [ D,E,T ] )
( [ ] , [ D,E,D ] )
( [ D ] , [ D,E,T ] )
( [ ] , [ D,E,D ] )
( [ E ] , [ D,E,D ] )
0:
2:
1:
3:
21
Peter Müller – Concepts of Object-Oriented Programming
Inference Example
4.1 Types – Bytecode Verification
0: aload 0
1: astore 2
2: aload 1
3: goto 1
in out
C
ED
worklist
3
( [ ] , [ D,E,T ] )
( [ D ] , [ D,E,T ] )
( [ ] , [ D,E,D ] )
( [ E ] , [ D,E,D ] )
( [ D ] , [ D,E,T ] )
( [ ] , [ D,E,D ] )
( [ E ] , [ D,E,D ] )
0:
2:
1:
3:
21
Peter Müller – Concepts of Object-Oriented Programming
Inference Example
4.1 Types – Bytecode Verification
0: aload 0
1: astore 2
2: aload 1
3: goto 1
in out
C
ED
worklist
( [ ] , [ D,E,T ] )
( [ D ] , [ D,E,T ] )
( [ ] , [ D,E,D ] )
( [ E ] , [ D,E,D ] )
( [ D ] , [ D,E,T ] )
( [ ] , [ D,E,D ] )
( [ E ] , [ D,E,D ] )
0:
2:
1:
3:
21
Peter Müller – Concepts of Object-Oriented Programming
Inference Example
4.1 Types – Bytecode Verification
0: aload 0
1: astore 2
2: aload 1
3: goto 1
in out
C
ED
worklist
( [ ] , [ D,E,T ] )
( [ D ] , [ D,E,T ] )
( [ ] , [ D,E,D ] )
( [ E ] , [ D,E,D ] )
( [ D ] , [ D,E,T ] )
( [ ] , [ D,E,D ] )
( [ E ] , [ D,E,D ] )
( [ E ] , [ D,E,D ] )
0:
2:
1:
3:
21
Peter Müller – Concepts of Object-Oriented Programming
Inference Example
4.1 Types – Bytecode Verification
0: aload 0
1: astore 2
2: aload 1
3: goto 1
in out
C
ED
worklist
( [ ] , [ D,E,T ] )
( [ D ] , [ D,E,T ] )
( [ C ] , [ D,E,T ] )
( [ ] , [ D,E,D ] )
( [ E ] , [ D,E,D ] )
( [ D ] , [ D,E,T ] )
( [ ] , [ D,E,D ] )
( [ E ] , [ D,E,D ] )
( [ E ] , [ D,E,D ] )
0:
2:
1:
3:
21
Peter Müller – Concepts of Object-Oriented Programming
Inference Example
4.1 Types – Bytecode Verification
0: aload 0
1: astore 2
2: aload 1
3: goto 1
in out
C
ED
worklist
1
( [ ] , [ D,E,T ] )
( [ D ] , [ D,E,T ] )
( [ C ] , [ D,E,T ] )
( [ ] , [ D,E,D ] )
( [ E ] , [ D,E,D ] )
( [ D ] , [ D,E,T ] )
( [ ] , [ D,E,D ] )
( [ E ] , [ D,E,D ] )
( [ E ] , [ D,E,D ] )
0:
2:
1:
3:
21
Peter Müller – Concepts of Object-Oriented Programming
Inference Example
4.1 Types – Bytecode Verification
0: aload 0
1: astore 2
2: aload 1
3: goto 1
in out
C
ED
worklist
( [ ] , [ D,E,T ] )
( [ D ] , [ D,E,T ] )
( [ C ] , [ D,E,T ] )
( [ ] , [ D,E,D ] )
( [ E ] , [ D,E,D ] )
( [ D ] , [ D,E,T ] )
( [ ] , [ D,E,D ] )
( [ E ] , [ D,E,D ] )
( [ E ] , [ D,E,D ] )
0:
2:
1:
3:
21
Peter Müller – Concepts of Object-Oriented Programming
Inference Example
4.1 Types – Bytecode Verification
0: aload 0
1: astore 2
2: aload 1
3: goto 1
in out
C
ED
worklist
( [ ] , [ D,E,T ] )
( [ D ] , [ D,E,T ] )
( [ C ] , [ D,E,T ] )
( [ ] , [ D,E,D ] )
( [ E ] , [ D,E,D ] )
( [ D ] , [ D,E,T ] )
( [ ] , [ D,E,D ] )
( [ ] , [ D,E,C ] )
( [ E ] , [ D,E,D ] )
( [ E ] , [ D,E,D ] )
0:
2:
1:
3:
21
Peter Müller – Concepts of Object-Oriented Programming
Inference Example
4.1 Types – Bytecode Verification
0: aload 0
1: astore 2
2: aload 1
3: goto 1
in out
C
ED
worklist
( [ ] , [ D,E,T ] )
( [ D ] , [ D,E,T ] )
( [ C ] , [ D,E,T ] )
( [ ] , [ D,E,D ] )
( [ ] , [ D,E,C ] )
( [ E ] , [ D,E,D ] )
( [ D ] , [ D,E,T ] )
( [ ] , [ D,E,D ] )
( [ ] , [ D,E,C ] )
( [ E ] , [ D,E,D ] )
( [ E ] , [ D,E,D ] )
0:
2:
1:
3:
21
Peter Müller – Concepts of Object-Oriented Programming
Inference Example
4.1 Types – Bytecode Verification
0: aload 0
1: astore 2
2: aload 1
3: goto 1
in out
C
ED
worklist
2
( [ ] , [ D,E,T ] )
( [ D ] , [ D,E,T ] )
( [ C ] , [ D,E,T ] )
( [ ] , [ D,E,D ] )
( [ ] , [ D,E,C ] )
( [ E ] , [ D,E,D ] )
( [ D ] , [ D,E,T ] )
( [ ] , [ D,E,D ] )
( [ ] , [ D,E,C ] )
( [ E ] , [ D,E,D ] )
( [ E ] , [ D,E,D ] )
0:
2:
1:
3:
21
Peter Müller – Concepts of Object-Oriented Programming
Inference Example
4.1 Types – Bytecode Verification
0: aload 0
1: astore 2
2: aload 1
3: goto 1
in out
C
ED
worklist
( [ ] , [ D,E,T ] )
( [ D ] , [ D,E,T ] )
( [ C ] , [ D,E,T ] )
( [ ] , [ D,E,D ] )
( [ ] , [ D,E,C ] )
( [ E ] , [ D,E,D ] )
( [ D ] , [ D,E,T ] )
( [ ] , [ D,E,D ] )
( [ ] , [ D,E,C ] )
( [ E ] , [ D,E,D ] )
( [ E ] , [ D,E,D ] )
0:
2:
1:
3:
21
Peter Müller – Concepts of Object-Oriented Programming
Inference Example
4.1 Types – Bytecode Verification
0: aload 0
1: astore 2
2: aload 1
3: goto 1
in out
C
ED
worklist
( [ ] , [ D,E,T ] )
( [ D ] , [ D,E,T ] )
( [ C ] , [ D,E,T ] )
( [ ] , [ D,E,D ] )
( [ ] , [ D,E,C ] )
( [ E ] , [ D,E,D ] )
( [ D ] , [ D,E,T ] )
( [ ] , [ D,E,D ] )
( [ ] , [ D,E,C ] )
( [ E ] , [ D,E,D ] )
( [ E ] , [ D,E,C ] )
( [ E ] , [ D,E,D ] )
0:
2:
1:
3:
21
Peter Müller – Concepts of Object-Oriented Programming
Inference Example
4.1 Types – Bytecode Verification
0: aload 0
1: astore 2
2: aload 1
3: goto 1
in out
C
ED
worklist
( [ ] , [ D,E,T ] )
( [ D ] , [ D,E,T ] )
( [ C ] , [ D,E,T ] )
( [ ] , [ D,E,D ] )
( [ ] , [ D,E,C ] )
( [ E ] , [ D,E,D ] )
( [ E ] , [ D,E,C ] )
( [ D ] , [ D,E,T ] )
( [ ] , [ D,E,D ] )
( [ ] , [ D,E,C ] )
( [ E ] , [ D,E,D ] )
( [ E ] , [ D,E,C ] )
( [ E ] , [ D,E,D ] )
0:
2:
1:
3:
21
Peter Müller – Concepts of Object-Oriented Programming
Inference Example
4.1 Types – Bytecode Verification
0: aload 0
1: astore 2
2: aload 1
3: goto 1
in out
C
ED
worklist
3
( [ ] , [ D,E,T ] )
( [ D ] , [ D,E,T ] )
( [ C ] , [ D,E,T ] )
( [ ] , [ D,E,D ] )
( [ ] , [ D,E,C ] )
( [ E ] , [ D,E,D ] )
( [ E ] , [ D,E,C ] )
( [ D ] , [ D,E,T ] )
( [ ] , [ D,E,D ] )
( [ ] , [ D,E,C ] )
( [ E ] , [ D,E,D ] )
( [ E ] , [ D,E,C ] )
( [ E ] , [ D,E,D ] )
0:
2:
1:
3:
21
Peter Müller – Concepts of Object-Oriented Programming
Inference Example
4.1 Types – Bytecode Verification
0: aload 0
1: astore 2
2: aload 1
3: goto 1
in out
C
ED
worklist
( [ ] , [ D,E,T ] )
( [ D ] , [ D,E,T ] )
( [ C ] , [ D,E,T ] )
( [ ] , [ D,E,D ] )
( [ ] , [ D,E,C ] )
( [ E ] , [ D,E,D ] )
( [ E ] , [ D,E,C ] )
( [ D ] , [ D,E,T ] )
( [ ] , [ D,E,D ] )
( [ ] , [ D,E,C ] )
( [ E ] , [ D,E,D ] )
( [ E ] , [ D,E,C ] )
( [ E ] , [ D,E,D ] )
0:
2:
1:
3:
21
Peter Müller – Concepts of Object-Oriented Programming
Inference Example
4.1 Types – Bytecode Verification
0: aload 0
1: astore 2
2: aload 1
3: goto 1
in out
C
ED
worklist
( [ ] , [ D,E,T ] )
( [ D ] , [ D,E,T ] )
( [ C ] , [ D,E,T ] )
( [ ] , [ D,E,D ] )
( [ ] , [ D,E,C ] )
( [ E ] , [ D,E,D ] )
( [ E ] , [ D,E,C ] )
( [ D ] , [ D,E,T ] )
( [ ] , [ D,E,D ] )
( [ ] , [ D,E,C ] )
( [ E ] , [ D,E,D ] )
( [ E ] , [ D,E,C ] )
( [ E ] , [ D,E,D ] )
( [ E ] , [ D,E,C ] )
0:
2:
1:
3:
21
Peter Müller – Concepts of Object-Oriented Programming
Inference Example
4.1 Types – Bytecode Verification
0: aload 0
1: astore 2
2: aload 1
3: goto 1
in out
C
ED
worklist
( [ ] , [ D,E,T ] )
( [ D ] , [ D,E,T ] )
( [ C ] , [ D,E,T ] )
( [ C ] , [ D,E,T ] )
( [ ] , [ D,E,D ] )
( [ ] , [ D,E,C ] )
( [ E ] , [ D,E,D ] )
( [ E ] , [ D,E,C ] )
( [ D ] , [ D,E,T ] )
( [ ] , [ D,E,D ] )
( [ ] , [ D,E,C ] )
( [ E ] , [ D,E,D ] )
( [ E ] , [ D,E,C ] )
( [ E ] , [ D,E,D ] )
( [ E ] , [ D,E,C ] )
0:
2:
1:
3:
21
22
Type Inference: Discussion
▪ Advantages
- Determines the most general solution that satisfies the
typing rules
- Might be more general than what is permitted by
compiler
- Very little type information required in class file
▪ Disadvantages
- Fixpoint computations may be slow
- Solution for interfaces is imprecise and requires run-time
checks
▪ Alternative: type checking (since Java 6)
Peter Müller – Concepts of Object-Oriented Programming
4.1 Types – Bytecode Verification
23
Bytecode Verification via Type Checking
▪ Extend class file to store type information
▪ Type information can be declared for each
bytecode instruction
▪ Type information required at the beginning of all
basic blocks:
- At jump target
- At entry point of exception handler
▪ Computation of SCS no longer necessary
- Avoid fixpoint computation and interface problem
Peter Müller – Concepts of Object-Oriented Programming
( [ int ] , [ C,int,T ] )
Includes
all join points
4.1 Types – Bytecode Verification
24
Peter Müller – Concepts of Object-Oriented Programming
Type Checking Algorithm
▪ Use and check declared types wherever available
▪ Infer types otherwise
4.1 Types – Bytecode Verification
foreach basic block of a method body do
in := types( start )
foreach { i instri is an instruction of basic block } do
in := apply_rule( instri, in )
foreach q in successors( i ) do
if types( q ) is declared then
check that in is assignable to types( q )
end
end
end
Required
types
Check conditions and infer
next configuration
Check
declared types
Type Checking Example
Peter Müller – Concepts of Object-Oriented Programming
0: aload 0
2: aload 1
3: goto 1
1: astore 2
C
ED
4.1 Types – Bytecode Verification 25
Type Checking Example
Peter Müller – Concepts of Object-Oriented Programming
0: aload 0
2: aload 1
3: goto 1
1: astore 2
( [ ] , [ D,E,T ] )
( [ C ] , [ D,E,T ] )
( [ ] , [ D,E,C ] )
C
ED
4.1 Types – Bytecode Verification 25
Type Checking Example
Peter Müller – Concepts of Object-Oriented Programming
0: aload 0
2: aload 1
3: goto 1
1: astore 2
( [ ] , [ D,E,T ] )
( [ C ] , [ D,E,T ] )
( [ ] , [ D,E,C ] )
C
ED
( [ D ] , [ D,E,T ] )
Rule application
4.1 Types – Bytecode Verification 25
Type Checking Example
Peter Müller – Concepts of Object-Oriented Programming
0: aload 0
2: aload 1
3: goto 1
1: astore 2
( [ ] , [ D,E,T ] )
( [ C ] , [ D,E,T ] )
( [ ] , [ D,E,C ] )
C
ED
( [ D ] , [ D,E,T ] )
Rule application
4.1 Types – Bytecode Verification 25
Type Checking Example
Peter Müller – Concepts of Object-Oriented Programming
0: aload 0
2: aload 1
3: goto 1
1: astore 2
( [ ] , [ D,E,T ] )
( [ C ] , [ D,E,T ] )
( [ ] , [ D,E,C ] )
C
ED
( [ D ] , [ D,E,T ] )
Rule application
( [ ] , [ D,E,C ] )
Rule application
4.1 Types – Bytecode Verification 25
Type Checking Example
Peter Müller – Concepts of Object-Oriented Programming
0: aload 0
2: aload 1
3: goto 1
1: astore 2
( [ ] , [ D,E,T ] )
( [ C ] , [ D,E,T ] )
( [ ] , [ D,E,C ] )
C
ED
( [ D ] , [ D,E,T ] )
Rule application
( [ ] , [ D,E,C ] )
Rule application
4.1 Types – Bytecode Verification 25
Type Checking Example
Peter Müller – Concepts of Object-Oriented Programming
0: aload 0
2: aload 1
3: goto 1
1: astore 2
( [ ] , [ D,E,T ] )
( [ C ] , [ D,E,T ] )
( [ ] , [ D,E,C ] )
C
ED
( [ D ] , [ D,E,T ] )
Rule application
( [ E ] , [ D,E,C ] )Rule application
( [ ] , [ D,E,C ] )
Rule application
4.1 Types – Bytecode Verification 25
Type Checking Example
Peter Müller – Concepts of Object-Oriented Programming
0: aload 0
2: aload 1
3: goto 1
1: astore 2
( [ ] , [ D,E,T ] )
( [ C ] , [ D,E,T ] )
( [ ] , [ D,E,C ] )
C
ED
( [ D ] , [ D,E,T ] )
Rule application
( [ E ] , [ D,E,C ] )
Rule application
( [ E ] , [ D,E,C ] )Rule application
( [ ] , [ D,E,C ] )
Rule application
4.1 Types – Bytecode Verification 25
Type Checking Example
Peter Müller – Concepts of Object-Oriented Programming
0: aload 0
2: aload 1
3: goto 1
1: astore 2
( [ ] , [ D,E,T ] )
( [ C ] , [ D,E,T ] )
( [ ] , [ D,E,C ] )
C
ED
( [ D ] , [ D,E,T ] )
Rule application
( [ E ] , [ D,E,C ] )
Rule application
( [ E ] , [ D,E,C ] )Rule application
( [ ] , [ D,E,C ] )
Rule application
4.1 Types – Bytecode Verification 25
26
Peter Müller – Concepts of Object-Oriented Programming
Bytecode Verification: Summary
▪ Bytecode verification enables secure mobile code
- For programs written in typed bytecode
▪ Bytecode verification can be done via type
inference or type checking
▪ Some run-time type checks are still necessary
- For instance, casts and co-variant arrays
4.1 Types – Bytecode Verification
27
Type Inference for Source Programs
▪ Type inference can
also be done on
source code
- For example, C# 3.0
and Scala infer types
of local variables
- Reduce annotation
overhead, especially
with generics
▪ Type annotations can
still be used to
support inference
Peter Müller – Concepts of Object-Oriented Programming
def sum( a: Array[ Int ] ): Int = {
val it = a.elements
var s = 0;
while( it.hasNext ) { s = s + it.next }
s
} Scala
def client = {
var a = 1
a = "Hello"
}Scala
def client = {
var a: Any = 1
a = "Hello"
}Scala
4.1 Types – Bytecode Verification
28
Type Inference vs. Dynamic Typing
▪ Type inference determines
the static type automatically
and then performs static
type checking
▪ Dynamic typing does not
require a static type and
does not perform static type
checking
Peter Müller – Concepts of Object-Oriented Programming
void client( ) {
var a = 1;
a = "Hello";
}C#
void client( ) {
dynamic a = 1;
a = "Hello";
}C#
4.1 Types – Bytecode Verification
29
Inference of Method and Field Types
▪ Inference of method
signatures generally
requires knowledge of all
implementations
▪ Inference of field types
generally requires
knowledge of all
assignments to the field
▪ Inference of these types is
non-modular
- Or based on speculation
Peter Müller – Concepts of Object-Oriented Programming
class A {
var f = 5;
def foo( p: Int ) = {
p
}
}Scala
class B extends A {
f = “Hello”;
override def foo( p: Int ) = {
“Hello”
}
}Scala
Inference:
f: Int
Inference:
foo returns Int
4.1 Types – Bytecode Verification
30
Peter Müller – Concepts of Object-Oriented Programming
4. Types
4.1 Bytecode Verification
4.2 Parametric Polymorphism
4. Types
31
Polymorphism Revisited
▪ Not all polymorphic
code is best
expressed using
subtype polymorphism
▪ Recovering precise
type information
requires downcasts
▪ Subtype relations are
sometimes not
desirable
- E.g., covariant arrays
Peter Müller – Concepts of Object-Oriented Programming
class Queue {
Object elem;
Queue next;
void enqueue( Object e ) { … }
Object dequeue( ) { … }
}
Queue q = new Queue( );
String s = “Hello”;
q.enqueue( s );
String t = ( String ) q.dequeue( );
Java
Java
static void fill( Object[ ] a, Object val )
{ … }Java
4.2 Types – Parametric Polymorphism
32
Parametric Polymorphism
▪ Classes and methods
can be parameterized
with types
▪ Clients provide
instantiations for type
parameters
▪ Modularity: generic
code is type checked
once and for all
(without knowing the
instantiations)
Peter Müller – Concepts of Object-Oriented Programming
class Queue<T> {
T elem;
Queue<T> next;
void enqueue( T e ) { … }
T dequeue( ) { … }
}
Queue<String> q;
q = new Queue<String>( );
String s = “Hello”;
q.enqueue( s );
String t = q.dequeue( );
Java
Java
static <T> void fill( T[ ] a, T val )
{ … }Java
4.2 Types – Parametric Polymorphism
33
Type Checking Generic Code
▪ Type checking a
generic class often
requires information
about its type
arguments
- Availability of methods
▪ Constraints can be
expressed by
specifying upper
bounds on type
parameters
Peter Müller – Concepts of Object-Oriented Programming
class Queue<T> {
T elem;
Queue<T> next;
void enqueue( T e ) {
if( next == null ) { … }
else {
if( e.compareTo( elem ) <= 0 ) {
next.enqueue( elem );
elem = e;
} else next.enqueue( e );
}
}
…
}Java
4.2 Types – Parametric Polymorphism
34
Upper Bounds: Example
Peter Müller – Concepts of Object-Oriented Programming
class Queue<T extends Comparable<T>> {
T elem;
Queue<T> next;
void enqueue( T e ) {
if( next == null ) { … }
else {
if( e.compareTo( elem ) <= 0 ) {
next.enqueue( elem );
elem = e;
} else next.enqueue( e );
}
}
…
}
interface Comparable<T> {
int compareTo( T o );
}
Java
Java
Queue<String> q;
// String implements Comparable<String>
Java
Queue<Person> q;
// Person does not implement Comparable<Person>
Java
Type check under
the assumption
T <: Comparable<T>
Typecheck under the
assumption
T <: Comparable<T>
4.2 Types – Parametric Polymorphism
35
Subtyping and Generics
▪ Generic types are
subtypes of their
declared supertypes
▪ Type variables are
subtypes of their upper
bounds
▪ How about different
instantiations of the
same generic class?
Peter Müller – Concepts of Object-Oriented Programming
class Queue<T extends Comparable<T>> { … }
Object o = new Queue<String>( );
void foo( T p ) {
Comparable<T> v = p;
}
List<Person> o;
o = new List<Student>( );
o = new List<Object>( );
4.2 Types – Parametric Polymorphism
36
Covariant Type Arguments
▪ Covariance:
If S <: T then
C<S> <: C<T>
▪ Covariance is unsafe
when a generic type
argument is used for
variables that are
written by clients
- Mutable fields
- Method arguments
Peter Müller – Concepts of Object-Oriented Programming
class Queue<T> {
void enqueue( T e ) { … }
T dequeue( ) { … }
}
void put( Queue<Object> q ) {
q.enqueue( “Hello” );
}
Object get( Queue<Object> q ) {
return q.dequeue( );
}
Not type safe if q had
type Queue<Integer>
4.2 Types – Parametric Polymorphism
37
Contravariant Type Arguments
▪ Contravariance:
If S <: T then
C<T> <: C<S>
▪ Contravariance is
unsafe when a generic
type argument is used
for variables that are
read by clients
- Fields
- Method results
Peter Müller – Concepts of Object-Oriented Programming
class Queue<T> {
void enqueue( T e ) { … }
T dequeue( ) { … }
}
void put( Queue<String> q ) {
q.enqueue( “Hello” );
}
String get( Queue<String> q ) {
return q.dequeue( );
}Not type safe if q had
type Queue<Object>
4.2 Types – Parametric Polymorphism
38
Java/C# Solution: Non-Variance
▪ Generic types in Java/C#
are non-variant (neither
co- nor contravariant)
▪ Non-variance is statically
type safe
- No run-time checks needed
▪ Non-variance is
sometimes overly
restrictive
Peter Müller – Concepts of Object-Oriented Programming
class Queue<T> {
void enqueue( T e ) { … }
T dequeue( ) { … }
}
Queue<String> o;
o = new Queue<Object>( );
Queue<Object> o;
o = new Queue<String>( );
Java
Java
Java
class Random<T> {
T next( ) { … }
}
4.2 Types – Parametric Polymorphism
39
Java/C#: Generics vs. Arrays
Peter Müller – Concepts of Object-Oriented Programming
Object[ ] o;
o = new String[ 5 ];Java
▪ Run-time checks
- Covariant arrays require run-time checks for each update
- Covariant generics would need checks for field updates
and argument passing
▪ Covariant generics would require more run-time
checks in more bytecode instructions
▪ Recall: Java/C# arrays
are covariant
▪ But an array T[ ] is not
much different from a
class Array<T>
Queue<Object> o;
o = new Queue<String>( );Java
4.2 Types – Parametric Polymorphism
40
o: Queue[ ANY ]
s: Queue[ STRING ]
create o.make
s := o
Eiffel Solution: Covariance
▪ Generic types in Eiffel are
covariant
▪ Design is consistent with
covariance for method
arguments and fields
- But not statically type safe
Peter Müller – Concepts of Object-Oriented Programming
class Queue[ T ] … end
o: Queue[ ANY ]
s: Queue[ STRING ]
create s.make
o := s
Eiffel
Eiffel
Eiffel
4.2 Types – Parametric Polymorphism
42
Scala Solution: Variance Annotations
▪ By default, generic types
in Scala are non-variant
▪ Programmers can supply
variance annotations to
allow co- and
contravariance
▪ Type checker imposes
restrictions on use of
variance annotations
Peter Müller – Concepts of Object-Oriented Programming
class Queue[ T ] {
def enqueue( e: T ) = { … }
def dequeue: T = { … }
}
Queue[ String ] o;
o = new Queue[ AnyRef ]( );
Queue[ AnyRef ] o;
o = new Queue[ String ]( );
Scala
Scala
Scala
4.2 Types – Parametric Polymorphism
43
Covariance Annotations
▪ A covariance annotation
(+) is useful when type
variable occurs only in
positive positions
- Result type
- Types of immutable fields
▪ Type checker prevents
other occurrences
Peter Müller – Concepts of Object-Oriented Programming
class Random[ +T ] {
def next: T = { … }
}
val r: Random[ AnyRef ] =
new Random[ String ]( )
val a = r.next
Scala
Scala
class Random[ +T ] {
def next: T = { … }
def initialze( i: T ) = { … }
}Scala
4.2 Types – Parametric Polymorphism
44
Contravariance Annotations
▪ A contravariance
annotation (-) is useful
when type variable
occurs only in negative
positions
- Parameter type
▪ Type checker prevents
other occurrences
Peter Müller – Concepts of Object-Oriented Programming
class OutputChannel[ -T ] {
def write( x: T ) = { … }
def lastWritten: T = { … }
}Scala
class OutputChannel[ -T ] {
def write( x: T ) = { … }
} Scala
val o: OutputChannel[ String ] =
new OutputChannel[ AnyRef ]( )
o.write( “Hello” )Scala
4.2 Types – Parametric Polymorphism
45
Working with Non-Variant Generics
▪ How can we write code that works with many
different instantiations of a generic class?
▪ Solution 1: Additional type parameters
Peter Müller – Concepts of Object-Oriented Programming
static <T> void printAll( Collection<T> c ) {
for ( T e : c ) { System.out.println( e ); }
}Java
static void printAll( Collection<Object> c ) {
for ( Object e : c ) { System.out.println( e ); }
}Java
4.2 Types – Parametric Polymorphism
foo( Collection<String> p ) {
printAll( p ) {
}Java
foo( Collection<String> p ) {
printAll( p ) {
}Java
46
Additional Type Parameters
Peter Müller – Concepts of Object-Oriented Programming
interface Comparator<T> {
int compare( T fst, T snd );
}
class TreeSet<E> {
TreeSet( Comparator<E> c ) { … }
… }
class Person { … } class Student extends Person { … }
TreeSet<Student> s = new TreeSet<Student>( new PersonComp() );
class PersonComp implements Comparator<Person> {
int compare( Person fst, Person snd ) { … }
}
TreeSet needs to
compare set elements
Universal comparator
for all persons
TreeSet<Student> s = new TreeSet<Student>( new PersonComp() );
Compile-time error: PersonComp is not
a subtype of Comparator<Student>
4.2 Types – Parametric Polymorphism
47
Additional Type Parameters (cont’d)
▪ Drawbacks
- Additional type argument is a nuisance for clients and
reveals implementation details
- Type-instantiation of Comparator cannot be changed at
runtime, for instance, to Comparator<Object>
Peter Müller – Concepts of Object-Oriented Programming
interface Comparator<T> {
int compare( T fst, T snd );
}
class TreeSet<F, E extends F> {
TreeSet( Comparator<F> c ) { … }
… }
TreeSet<Person, Student> s =
new TreeSet<Person, Student>( new PersonComp() );
Comparator can
compare at least Es
4.2 Types – Parametric Polymorphism
48
Solution 2: Wildcards
▪ A wildcard represents an unknown type
Peter Müller – Concepts of Object-Oriented Programming
static <T> void printAll( Collection<T> c ) {
for ( T e : c ) { System.out.println( e ); }
}Java
static void printAll( Collection<?> c ) {
for ( Object e : c ) { System.out.println( e ); }
}Java
4.2 Types – Parametric Polymorphism
49
Wildcards and Existential Types
▪ Interpretation as existential type
- “There exists a type argument T such that c has type
Collection<T>”
- Existential quantifier is instantiated automatically by the
type system
Peter Müller – Concepts of Object-Oriented Programming
static void printAll( Collection<?> c ) {
for ( Object e : c ) { System.out.println( e ); }
} Java
Collection<String> c = new ArrayList<String>( );
…
printAll( c ); JavaWildcard instantiated
with String
4.2 Types – Parametric Polymorphism
50
Wildcard Examples
Peter Müller – Concepts of Object-Oriented Programming
static Collection<?> id( Collection<?> c ) {
return c;
}
Collection<String> c = new ArrayList<String>( );
Collection<String> d = id( c );
Two existential
types
Two existential
types
4.2 Types – Parametric Polymorphism
Correct: type checker
instantiates type argument
with c’s type argument
Collection<String> c = new ArrayList<String>( );
Collection<String> d = id( c );
Type error: existential
types might have
different instantiations
(modular type checking)
51
Wildcard Examples (cont’d)
Peter Müller – Concepts of Object-Oriented Programming
static void merge( Collection<?> c, Collection<?> d ) {
for( Object e : c ) { d.add( e ); }
}Two existential
types
4.2 Types – Parametric Polymorphism
static void merge( Collection<?> c, Collection<?> d ) {
for( Object e : c ) { d.add( e ); }
}Two existential
types
Type error: d might
expect elements of
different type
52
Wildcard Examples (cont’d)
Peter Müller – Concepts of Object-Oriented Programming
class Spooler {
Collection<?> task;
void setTask( Collection<?> c ) {
task = c;
}
void print( ) {
for ( Object e : task ) { System.out.println( e ); }
}
}
Cannot be simulated
with method type
parameters
4.2 Types – Parametric Polymorphism
Correct: type checker
instantiates task’s type
argument with c’s
Works because
every Java object
has toString method
53
Constrained Wildcards
Peter Müller – Concepts of Object-Oriented Programming
4.2 Types – Parametric Polymorphism
static void printFormatted( Collection<?> c ) {
for ( Object e : c ) {
String s = e.format( 80 );
System.out.println( s );
}
}Type error: elements
might not support
method format
54
Constrained Wildcards: Upper Bounds
Peter Müller – Concepts of Object-Oriented Programming
4.2 Types – Parametric Polymorphism
static void printFormatted( Collection<? extends Format> c ) {
for ( Format e : c ) {
String s = e.format( 80 );
System.out.println( s );
}
}
interface Format {
String format( int width );
}
Typecheck under the
assumption
? <: Format
Collection<Object> c = new ArrayList<Object>( );
printFormatted( c );
Compile-time error:
Object is not a subtype of
the upper bound Format
More Bounded Wildcards
Peter Müller – Concepts of Object-Oriented Programming
class Cell<T> {
T value;
void copyFromT( Cell<T> other ) {
value = other.value;
}
}
4.2 Types – Parametric Polymorphism 55
More Bounded Wildcards
Peter Müller – Concepts of Object-Oriented Programming
class Cell<T> {
T value;
void copyFromT( Cell<T> other ) {
value = other.value;
}
}
Overly
restrictive
4.2 Types – Parametric Polymorphism 55
More Bounded Wildcards
Peter Müller – Concepts of Object-Oriented Programming
class Cell<T> {
T value;
void copyFromT( Cell<T> other ) {
value = other.value;
}
}
class Cell<T> {
T value;
void copyFromT( Cell<T> other ) {
value = other.value;
}
void copyFrom( Cell<?> other ) {
value = other.value;
}
}
4.2 Types – Parametric Polymorphism 55
More Bounded Wildcards
Peter Müller – Concepts of Object-Oriented Programming
class Cell<T> {
T value;
void copyFromT( Cell<T> other ) {
value = other.value;
}
}
class Cell<T> {
T value;
void copyFromT( Cell<T> other ) {
value = other.value;
}
void copyFrom( Cell<?> other ) {
value = other.value;
}
}
Not type
correct
4.2 Types – Parametric Polymorphism 55
More Bounded Wildcards
Peter Müller – Concepts of Object-Oriented Programming
class Cell<T> {
T value;
void copyFromT( Cell<T> other ) {
value = other.value;
}
}
class Cell<T> {
T value;
void copyFromT( Cell<T> other ) {
value = other.value;
}
void copyFrom( Cell<?> other ) {
value = other.value;
}
}
Not type
correct
class Cell<T> {
T value;
void copyFromT( Cell<T> other ) {
value = other.value;
}
void copyFrom( Cell<? extends T> other ) {
value = other.value;
}
}
4.2 Types – Parametric Polymorphism 55
More Bounded Wildcards
Peter Müller – Concepts of Object-Oriented Programming
class Cell<T> {
T value;
void copyFromT( Cell<T> other ) {
value = other.value;
}
}
class Cell<T> {
T value;
void copyFromT( Cell<T> other ) {
value = other.value;
}
void copyFrom( Cell<?> other ) {
value = other.value;
}
}
Not type
correct
class Cell<T> {
T value;
void copyFromT( Cell<T> other ) {
value = other.value;
}
void copyFrom( Cell<? extends T> other ) {
value = other.value;
}
}
Typecheck under
the assumption
? <: T
4.2 Types – Parametric Polymorphism 55
More Bounded Wildcards
Peter Müller – Concepts of Object-Oriented Programming
class Cell<T> {
T value;
void copyFromT( Cell<T> other ) {
value = other.value;
}
}
Overly
restrictive
class Cell<T> {
T value;
void copyFromT( Cell<T> other ) {
value = other.value;
}
void copyFrom( Cell<?> other ) {
value = other.value;
}
}
Not type
correct
class Cell<T> {
T value;
void copyFromT( Cell<T> other ) {
value = other.value;
}
void copyFrom( Cell<? extends T> other ) {
value = other.value;
}
}
Typecheck under
the assumption
? <: T
class Cell<T> {
T value;
void copyFromT( Cell<T> other ) {
value = other.value;
}
void copyFrom( Cell<? extends T> other ) {
value = other.value;
}
void copyTo( Cell<?> other ) {
other.value = value;
}
}
4.2 Types – Parametric Polymorphism 55
More Bounded Wildcards
Peter Müller – Concepts of Object-Oriented Programming
class Cell<T> {
T value;
void copyFromT( Cell<T> other ) {
value = other.value;
}
}
class Cell<T> {
T value;
void copyFromT( Cell<T> other ) {
value = other.value;
}
void copyFrom( Cell<?> other ) {
value = other.value;
}
}
Not type
correct
class Cell<T> {
T value;
void copyFromT( Cell<T> other ) {
value = other.value;
}
void copyFrom( Cell<? extends T> other ) {
value = other.value;
}
}
Typecheck under
the assumption
? <: T
class Cell<T> {
T value;
void copyFromT( Cell<T> other ) {
value = other.value;
}
void copyFrom( Cell<? extends T> other ) {
value = other.value;
}
void copyTo( Cell<?> other ) {
other.value = value;
}
}
Not type
correct
4.2 Types – Parametric Polymorphism 55
More Bounded Wildcards
Peter Müller – Concepts of Object-Oriented Programming
class Cell<T> {
T value;
void copyFromT( Cell<T> other ) {
value = other.value;
}
}
class Cell<T> {
T value;
void copyFromT( Cell<T> other ) {
value = other.value;
}
void copyFrom( Cell<?> other ) {
value = other.value;
}
}
Not type
correct
class Cell<T> {
T value;
void copyFromT( Cell<T> other ) {
value = other.value;
}
void copyFrom( Cell<? extends T> other ) {
value = other.value;
}
}
Typecheck under
the assumption
? <: T
class Cell<T> {
T value;
void copyFromT( Cell<T> other ) {
value = other.value;
}
void copyFrom( Cell<? extends T> other ) {
value = other.value;
}
void copyTo( Cell<?> other ) {
other.value = value;
}
}
Not type
correct
class Cell<T> {
T value;
void copyFromT( Cell<T> other ) {
value = other.value;
}
void copyFrom( Cell<? extends T> other ) {
value = other.value;
}
void copyTo( Cell<? super T> other ) {
other.value = value;
}
}
Wildcard can
also have
lower bounds
4.2 Types – Parametric Polymorphism 55
More Bounded Wildcards
Peter Müller – Concepts of Object-Oriented Programming
class Cell<T> {
T value;
void copyFromT( Cell<T> other ) {
value = other.value;
}
}
class Cell<T> {
T value;
void copyFromT( Cell<T> other ) {
value = other.value;
}
void copyFrom( Cell<?> other ) {
value = other.value;
}
}
Not type
correct
class Cell<T> {
T value;
void copyFromT( Cell<T> other ) {
value = other.value;
}
void copyFrom( Cell<? extends T> other ) {
value = other.value;
}
}
Typecheck under
the assumption
? <: T
class Cell<T> {
T value;
void copyFromT( Cell<T> other ) {
value = other.value;
}
void copyFrom( Cell<? extends T> other ) {
value = other.value;
}
void copyTo( Cell<?> other ) {
other.value = value;
}
}
Not type
correct
class Cell<T> {
T value;
void copyFromT( Cell<T> other ) {
value = other.value;
}
void copyFrom( Cell<? extends T> other ) {
value = other.value;
}
void copyTo( Cell<? super T> other ) {
other.value = value;
}
}
Wildcard can
also have
lower bounds
Typecheck under
the assumption
T <: ?
4.2 Types – Parametric Polymorphism 55
56
Use-Site Variance: Covariance
▪ Wildcards allow clients to decide on variance at the
use site
- As opposed to Scala’s declaration-site variance
Peter Müller – Concepts of Object-Oriented Programming
class Random<T> {
T next( ) { … }
}Java
Random<? extends Person> =
new Random<Student >( );
Person a = r.next( );
r.initialize( new Student( ) );
4.2 Types – Parametric Polymorphism
class Random<T> {
T next( ) { … }
void initialize( T i ) { … }
}Java
Upper bound permits
covariant instantiation
Covariant uses
typecheck
Contravariant uses do
not typecheck
57
Use-Site Variance: Contravariance
Peter Müller – Concepts of Object-Oriented Programming
class OutputChannel<T> {
void write( T x ) { … }
}Java
OutputChannel<? super Student> o =
new OutputChannel<Person>( );
o.write( new Student( ) );
Person s = o.lastWritten( );
4.2 Types – Parametric Polymorphism
class OutputChannel<T> {
void write( T x ) { … }
T lastWritten( ) { … }
}Java
Lower bound permits
contravariant
instantiation
Contravariant uses
typecheck
Covariant uses do not
typecheck
58
TreeSet Revisited
Peter Müller – Concepts of Object-Oriented Programming
interface Comparator<T> {
int compare( T fst, T snd );
}
class TreeSet<E> {
TreeSet( Comparator<? super E> c ) { … }
… }
class Person { … } class Student extends Person { … }
TreeSet<Student> s = new TreeSet<Student>( new PersonComp() );
class PersonComp implements Comparator<Person> {
int compare( Person fst, Person snd ) { … }
}
TreeSet needs to compare
at least set elements
(use-site contravariance)
TreeSet<Student> s = new TreeSet<Student>( new PersonComp() );
Wildcard instantiated with Person,
which is a supertype of Student
4.2 Types – Parametric Polymorphism
59
Wildcards vs. Method Type Parameters
Peter Müller – Concepts of Object-Oriented Programming
void copyFrom( Cell<? extends T> other ) {
value = other.value;
}
<S super T> void copyTo( Cell<S> other ) {
other.value = value;
}
<S extends T> void copyFrom( Cell<S> other ) {
value = other.value;
}
void copyTo( Cell<? super T> other ) {
other.value = value;
}
Cell<String> s;
Cell<Object> o;
s = new Cell<String>();
o = new Cell<Object>();
o.copyFrom( s );
Identical client code:
instantiations of
wildcard and method
type argument are
inferred
Java does not support
lower bounds for type
parameters
4.2 Types – Parametric Polymorphism
60
Wildcards vs. Class Type Parameters
Peter Müller – Concepts of Object-Oriented Programming
class Wrapper {
Cell<?> data;
}
class Wrapper<T> {
Cell<T> data;
}
Wrapper w = new Wrapper( );
w.data = new Cell<String>( );
w.data = new Cell<Object>( );
Wrapper<Object> w = new Wrapper<Object>( );
w.data = new Cell<String>( );
w.data = new Cell<Object>( );
With type argument,
instantiation is fixed
when object is created
Instantiation can
change over time
4.2 Types – Parametric Polymorphism
61
Subtyping and Generics: Wildcards
▪ The bounds for a wildcard determine the set of
possible instantiations
▪ For types S and T with the same class or interface,
S is a subtype of T if for each type argument, the
set of possible instantiations for S is a subset of the
set of possible instantiations for T
Peter Müller – Concepts of Object-Oriented Programming
Cell<? extends Person> c;
Cell<? super PhDStudent> d;
4.2 Types – Parametric Polymorphism
c = new Cell<Student>( );
Cell<? extends Student> e = …;
c = e;
Instantiation is fixed
(singleton set)
62
Decidability
▪ Whether S is a subtype of T is undecidable in Java
due to wildcards
▪ In fact, Java generics are Turing-complete
Peter Müller – Concepts of Object-Oriented Programming
4.2 Types – Parametric Polymorphism
class T { }
class N<Z> { }
class C<X> extends N<N<? super C<C<X>>>> {
public N<? super C<T>> foo( C<T> c ) {
return c;
}
}
63
Type Erasure
▪ Java introduced generics in version 1.4
▪ For backwards compatibility, Sun did not want to
change the virtual machine
▪ Generic type information is erased by compiler
- C<T> is translated to C
- T is translated to its upper bound
- Casts are added where necessary
▪ Only one classfile and only one class object to
represent all instantiations of a generic class
Peter Müller – Concepts of Object-Oriented Programming
4.2 Types – Parametric Polymorphism
64
Type Erasure: Example
Peter Müller – Concepts of Object-Oriented Programming
class Cell<T extends Object> {
T value;
void set( T v ) {
value = v;
}
T get( ) {
return value;
}
}
Cell<String> c;
c = new Cell<String>( ) ;
c.set( “Hello” );
String s = c.get( );
class Cell {
Object value;
void set( Object v ) {
value = v;
}
Object get( ) {
return value;
}
}
Cell c;
c = new Cell( );
c.set( “Hello” );
String s = ( String ) c.get( );
4.2 Types – Parametric Polymorphism
65
Erasure: Missing Run-Time Information
Peter Müller – Concepts of Object-Oriented Programming
void foo( Cell<?> c ) {
if( c instanceof Cell<String> )
…
} Java
Class c = Cell<String>.class;Java
Cell<String>[ ] a;
a = new Cell<String>[10];Java
Compile-time error:
generic types not
allowed with instanceof
Compile-time error:
class object of generic
types not available
Compile-time error:
arrays of generic types
not allowed
4.2 Types – Parametric Polymorphism
66
Run-Time Information for Generics in C#
Peter Müller – Concepts of Object-Oriented Programming
void Foo( object c ) {
if( c is Cell<string> )
…
}
C# does not
have wildcards
C#
System.Type type = typeof( Cell<string> );C#
Cell<String>[ ] a;
a = new Cell<string>[10];C#C# can perform run-time
check for array update
C# has run-time
representation
C# can perform
dynamic type test
4.2 Types – Parametric Polymorphism
67
Erasure: Missing Run-Time Checks
Peter Müller – Concepts of Object-Oriented Programming
String demo( Cell<?> c ) {
Cell<String> cs = ( Cell<String> ) c;
…
return cs.value;
}Java
void main( ) {
Cell<Object> co = new Cell<Object>( );
co.value = new Integer( 5 );
demo( co );
} Java
Weak type invariant:
object in cs is not of
type Cell<String>!
No run-time
check for this
cast!
Run-time error:
cs.value is not
a string
4.2 Types – Parametric Polymorphism
68
▪ Static fields are shared by all instantiations of a
generic class
Erasure: Static Fields
Peter Müller – Concepts of Object-Oriented Programming
class Count<T> {
static int c = 0;
}
Count.c = 1;
Count.c = 2;
Java
Count<string>.c = 1;
Count<object>.c = 2;
C#
4.2 Types – Parametric Polymorphism
69
C++ Templates
▪ Templates allow
classes and methods
to be parameterized
▪ Clients provide
instantiations for
template parameters
Peter Müller – Concepts of Object-Oriented Programming
template<class T> class Queue {
T elem;
Queue<T>* next;
public:
void enqueue( T e ) { … };
T dequeue( void ) { … };
};
Queue<int> *q;
q = new Queue<int>( );
int s = 5;
q->enqueue( s );
int t = q->dequeue( );
C++
template<class T> void fill( T a[ ], T v )
{ … };C++
4.2 Types – Parametric Polymorphism
C++
70
Template Instantiation
Peter Müller – Concepts of Object-Oriented Programming
template<class T> class Queue {
T elem;
Queue<T>* next;
…
};
Queue<int> *q;
…
class Queueint {
int elem;
Queueint* next;
…
};
Queueint *q;
…
Template InstantiationCompiler generates
class for given
template instantiation
Client code uses
generated class
Type checking is
done for generated
class, not for template
4.2 Types – Parametric Polymorphism
71
template<class T> class Queue {
T elem; Queue<T>* next;
public:
void enqueue( T e ) {
if( next == NULL ) {
elem = e; next = new Queue<T>( );
} else {
if( e.compareTo( elem ) <= 0 )
{ next->enqueue( elem ); elem = e; }
else next->enqueue( e );
}
};
T dequeue( void ) { return “Hello”; };
};
template<class T> class Queue {
T elem; Queue<T>* next;
public:
void enqueue( T e ) {
if( next == NULL ) {
elem = e; next = new Queue<T>( );
} else {
if( e.compareTo( elem ) <= 0 )
{ next->enqueue( elem ); elem = e; }
else next->enqueue( e );
}
};
T dequeue( void ) { return “Hello”; };
};
Queue<int> *q;
q = new Queue<int>( );
Templates and Type Checking
Peter Müller – Concepts of Object-Oriented Programming
Compiler does not type
check template code
Queue<int> *q;
q = new Queue<int>( );
Queue<int> *q;
q = new Queue<int>( );
int s = 5;
q->enqueue( s );
int t = q->dequeue( );
Compiles even
though template
is instantiated
Queue<int> *q;
q = new Queue<int>( );
int s = 5;
q->enqueue( s );
int t = q->dequeue( );
Compile-time errors:
template methods
not type correct
Compiler does not
check availability
of methods
4.2 Types – Parametric Polymorphism
72
Templates and Type Checking (cont’d)
▪ Template code is type checked when instantiated
- Type errors are not detected before instantiation
▪ No need for upper bounds on type parameters
- Availability of methods is not checked anyway
- Template has to document (informally) what it expects
from its type arguments
▪ Different instantiations of templates are unrelated
- Use template methods to write polymorphic methods
▪ Templates do not require run-time support
- Run-time types correspond to generated classes
Peter Müller – Concepts of Object-Oriented Programming
4.2 Types – Parametric Polymorphism
73
Template Meta-Programming
Peter Müller – Concepts of Object-Oriented Programming
template<> class Fact<0> {
public:
static const int val = 1;
};
template<int n> class Fact {
public:
static const int val = Fact<n-1>::val * n;
};
int main( ) {
printf( "fact 3 = %d\n", Fact<3>::val );
printf( "fact 4 = %d\n", Fact<4>::val );
printf( "fact 5 = %d\n", Fact<5>::val );
return 0;
}
Template parameters
need not be types
Templates can
be specializedCompiler generates
these instantiations
Through constant
propagation, values
are computed by
compiler
4.2 Types – Parametric Polymorphism
74
Generic Types vs. Templates: Summary
Generic Types
▪ Modular type checking
of generic class
- Overhead
(e.g., upper bounds)
▪ Run-time support
desirable
▪ Typically no meta-
programming
Templates
▪ Type checking per
instantiation
- Flexibility like with
structural typing
▪ No need for run-time
support
▪ Meta-programming is
Turing-complete
Peter Müller – Concepts of Object-Oriented Programming
4.2 Types – Parametric Polymorphism
75
References
▪ Xavier Leroy: Java Bytecode Verification: Algorithms and
Formalizations. Journal of Automated Reasoning, 2003
▪ Tim Lindholm, Frank Yellin, Gilad Bracha, and Alex Buckley:
The Java Virtual Machine Specification. 2013
http://docs.oracle.com/javase/specs/
▪ Gilad Bracha, Martin Odersky, David Stoutamire, and
Philip Wadler: Making the Future Safe for the Past:
Adding Genericity to the Java Programming Language.
OOPSLA 1998
▪ Radu Grigore: Java generics are turing complete. POPL
2017
Peter Müller – Concepts of Object-Oriented Programming
4. Types