Professional Documents
Culture Documents
Jeremy Siek
University of Colorado at Boulder
SSGIP 2010
Jeremy Siek
1 / 78
2000
2010
Jeremy Siek
2 / 78
Generic Programming
Generic Programming is
higher-order, polymorphic programming
scaled up to large, complex families of algorithms
Jeremy Siek
3 / 78
Typical uses:
foldl op + 1.0 [2.0,3.0,4.0];
val it = 10.0 : real
foldl op 1 [2,3,4];
val it = 24 : int
foldl op @ [] [[1,2],[3],[4,5,6]];
val it = [4,5,6,3,1,2] : int list
Jeremy Siek
4 / 78
, ` e : T
` . e : .T
` e : .T
` e[S] : [ 7 S]T
Jeremy Siek
5 / 78
Jeremy Siek
6 / 78
Generic Programming
Jeremy Siek
7 / 78
Algebraic Structures
In Tecton [Kapur, Musser, Stepanov 1981]
create semigroup(S : set, +: SS S)
with x + (y + z) = (x + y) + z;
create monoid(S : semigroup, 0: () S)
with 0 + x = x + 0 = x;
integers(I : set, + : I I I, : I I I,
0 : () I, 1 : () I)
instantiate monoid of integers (S=I, + = +, 0 = 0)
instantiate monoid of integers (S=I, + = , 0 = 1)
Jeremy Siek
8 / 78
Algebraic Structures
Jeremy Siek
9 / 78
Jeremy Siek
10 / 78
I
I
I
I
I
Jeremy Siek
11 / 78
Example
I
I
I
I
Monoid is a concept.
Sequence is a concept.
int models Monoid.
array<int> models Sequence.
Jeremy Siek
12 / 78
Algorithms
Iterator Concepts
sort_heap
stable_sort
partition
binary_search
Containers
list
Forward
Bidirectional
Random Access
...
map
vector
set
T[]
...
merge
...
Jeremy Siek
13 / 78
Input
Random Access
Bidirectional
Forward
Output
I
I
Jeremy Siek
14 / 78
15 / 78
Documentation:
I
I
I
I
I
16 / 78
value type
difference type
Valid Expressions
(X is the iterator type, T is the value type)
expression
i
++i
return type
Convertible to T
X&
i == j
bool
i != j
bool
semantics
Returns the value at position i
Moves the iterator to the next position.
Returns true if i and j are at
the same position. i == j implies
i == j
Equivalent to !(i == j).
Complexity guarantees
All operations are amortized constant time.
Jeremy Siek
17 / 78
namespace std {
template <class T>
T min(T a, T b) {
if (b < a) return b; else return a;
}
}
int main() {
return min(3, 4);
}
Jeremy Siek
18 / 78
namespace std {
template <class T>
T min(T a, T b) {
if (b < a) return b; else return a;
}
}
int main() {
return min<int>(3, 4);
}
Jeremy Siek
19 / 78
20 / 78
21 / 78
namespace std {
template <class T>
T min(T a, T b) { if (b < a) return b; else return a; }
}
struct A {};
int main() {
A a;
std::min(a, a);
}
22 / 78
Jeremy Siek
23 / 78
stl algo.h: In function void std:: inplace stable sort( RandomAccessIter, RandomAccessIter)
[with RandomAccessIter = std:: List iterator<int, int&, int>]:
stl algo.h:2565: instantiated from void std::stable sort( RandomAccessIter, RandomAccessIter)
[with RandomAccessIter = std:: List iterator<int, int&, int>]
stable sort error.cpp:5: instantiated from here
stl algo.h:2345: error: no match for std:: List iterator<int, int&, int>& -std:: List iterator<int, int&, int>& operato
stl algo.h:2565: instantiated from void std::stable sort( RandomAccessIter, RandomAccessIter)
[with RandomAccessIter = std:: List iterator<int, int&, int>]
stable sort error.cpp:5: instantiated from here
stl algo.h:2349: error: no match for std:: List iterator<int, int&, int>& -std:: List iterator<int, int&, int>& operato
stl algo.h:2352: error: no match for std:: List iterator<int, int&, int>& -std:: List iterator<int, int&, int>& operato
stl algo.h:2352: error: no match for std:: List iterator<int, int&, int>& -std:: List iterator<int, int&, int>& operato
stl algo.h:2565: instantiated from void std::stable sort( RandomAccessIter, RandomAccessIter)
[with RandomAccessIter = std:: List iterator<int, int&, int>]
stable sort error.cpp:5: instantiated from here
stl algo.h:2095: error: no match for std:: List iterator<int, int&, int>& + int operator
stl algo.h:2346: instantiated from void std:: inplace stable sort( RandomAccessIter, RandomAccessIter)
[with RandomAccessIter = std:: List iterator<int, int&, int>]
stl algo.h:2565: instantiated from void std::stable sort( RandomAccessIter, RandomAccessIter)
[with RandomAccessIter = std:: List iterator<int, int&, int>]
...
The C++0x Concept Effort
24 / 78
Jeremy Siek
25 / 78
26 / 78
Jeremy Siek
27 / 78
28 / 78
29 / 78
30 / 78
31 / 78
32 / 78
33 / 78
34 / 78
External Adaptation
A particularly nice thing about traits is that you can
retroactively adapt third-party types.
namespace old third party {
class old iter { ... };
}
// adapt old iter to InputIterator concept
namespace std {
template<> struct iterator traits<old iter> {
typedef old iter::elt value type; ...
};
}
namespace old third party {
old iter::elt operator(old iter i) { return i.getCurrent(); }
old iter& operator++(old iter i) { i.next(); return i; }
}
Jeremy Siek
35 / 78
36 / 78
37 / 78
At Indiana University
1.
2.
3.
4.
5.
6.
At Texas A&M
1. Bjarne Stroustrup (Creator of C++)
2. Gabriel Dos Reis (Assistant Prof.)
Jeremy Siek
38 / 78
39 / 78
Definition
Concepts can be collaborations of many types.
More than one constraint on a type parameter.
Mappings between types.
Concepts may constrain associated types.
Modeling can be separate from type definition.
Generic functions are independently compiled.
Type arguments of a generic function can be
deduced. Also, the language finds models to
satisfy constraints of a generic function.
Generic functions are independently checked.
Model declarations are lexically scoped. Models
may be imported from other namespaces.
There can be multiple generic functions with
the same name but differing constraints.
Anonymous functions with lexical scoping that
are treated as first-class.
Jeremy Siek
40 / 78
Using
#
#
#
#
#
#
#
C#
#
#
#
#
#
#
#
#
# G
G
#
Java
#
# G
G
#
#
# G
G
# G
G
#
Haskell
#
G
#
#
OCaml
#
#
G
SML
#
G
C++
-
#
G
Multi-type concepts
Multiple constraints
Associated type access
Constraints on assoc. types
Retroactive modeling
Separate compilation
Implicit arg. deduction
Modular type checking
Lexically scoped models
Concept-based overloading
Same-type constriants
First-class functions
41 / 78
Concept Composition
template <(C1 && C2) T> class X { ... };
template <(C1 || C2) T> class Y { ... };
template <(C1 && !C2) T> class Z { ... };
42 / 78
Concept-based Overloading
template <InputIterator InIter>
void advance(InIter& i, InIter::difference type n)
{ while (n--) ++i; }
template <RandomAccessIterator RandIter>
void advance(RandIter& i, RandIter::difference type n)
{ i += n; }
Jeremy Siek
43 / 78
Jeremy Siek
44 / 78
Add::Add(Add);
T1 operator+(Add, Add);
Add::Add(T1);
45 / 78
Jeremy Siek
46 / 78
Jeremy Siek
47 / 78
Research at Indiana
Jeremy Siek
48 / 78
49 / 78
Jeremy Siek
50 / 78
Research at Indiana
I
I
Jeremy Siek
51 / 78
::=
::=
::=
|
|
|
|
::=
::=
Concept Names
Type Variables
Term Variables
c<T > | S = T
Constraints
| T T | .T | C T | .
x | e e | y : T . e | . e | e[T ]
C e | type = T in e
concept c<>{types ; requires C ; x : T } in e
model c<T > { types = S; x = e} in e
.x
c<T > | .c<T >
, x : T | , | , S = T | , c<T > | , c<T >{ = S}
52 / 78
53 / 78
Generic Algorithm in FG
let foldl =
( s. Seq<s>
type t = Seq<s>.value type in Monoid<t>
fix ( r : s t. ls : s.
let binary op = Monoid<t>.binary op in
let identity elt = Monoid<t>.identity elt in
if Seq<s>.is null ls then identity elt
else binary op(Seq<s>.head ls, r(Seq<s>.tail ls))))
in
foldl[int list] [2,3,4]
Jeremy Siek
54 / 78
Type Equality in FG
`S =T
` = 0
` . = 0 .
S =T
`S =T
() = { = S}
` .i = Si
` C1 = C2
`S =T
` (C1 S) = (C2 T )
` S1 = T1
` S2 = T2
` S1 S2 = T1 T2
` S = [ 7 ]T
` .S = .T
55 / 78
Jeremy Siek
56 / 78
, C ` e : T
`C e:T
, = S ` e : T
` type = S in e : T
` c<S>
` c<S>.xi : [ 7 S, 7 c<S>.]Ti
`C
c<T 0 > ` T = T 0
` c<T >
Jeremy Siek
` T = T0
` (T = T 0 )
The C++0x Concept Effort
57 / 78
Summary of FG
I
I
Jeremy Siek
58 / 78
A Larger Prototype: G
G adds the following on top of FG :
I
I
I
I
I
I
59 / 78
60 / 78
61 / 78
62 / 78
Example Concepts
template<typeid T>
concept LessThanComparable {
bool operator<(T a, T b);
bool operator>(T a, T b) {return b < a;}
bool operator<=(T a, T b) {return !(b < a);}
bool operator>=(T a, T b) {return !(a < b);}
};
template<typeid Iter>
concept InputIterator : EqualityComparable<Iter>,
CopyConstructible<Iter>, Assignable<Iter>
{
typename value type = Iter::value type;
typename difference type = Iter::difference type;
typename reference = Iter::reference;
require Convertible<reference, value type>;
Iter& operator++(Iter&);
reference operator(Iter);
};
Jeremy Siek
63 / 78
Example Models
model LessThanComparable<int> { };
model LessThanComparable<float> { };
template<typeid T>
model InputIterator<T> { };
template<typeid Iter>
where { BidirectionalIterator<Iter> }
model BidirectionalIterator< reverse iterator<Iter> > { };
Jeremy Siek
64 / 78
Jeremy Siek
65 / 78
Pseudo-Signatures
class A {};
class B : public A {};
template<typeid T>
concept C {
A f(T, B);
};
B f(A, A) { return B(); }
model C<A> { };
// This model is OK because B is convertible to A.
Jeremy Siek
66 / 78
67 / 78
usage patterns
general Boolean expressions allowed in where clauses
|| and ! operators on constraints
Models declarations are optional unless a concept has
associated types.
5. The proposal did not include a detailed semantics and
there was no prototype implementation.
Jeremy Siek
68 / 78
69 / 78
Over the next few months, the Indiana and Texas teams
wrote up the compromise design [OOPSLA 2006].
Gregor and Stroustrup wrote a revised proposal for the
standards committee: N2042, N2081.
The keyword model became concept map because a
survey showed that model appears too frequently in
C++ programs.
Jeremy Siek
70 / 78
Jeremy Siek
71 / 78
fast_vector
template<Foo T>
void super_sort(T);
Fred
Suzy
namespace Alex {
concept_map Foo<fast_vector> { };
}
void sort() {
John::fast_vector v;
Alex::super_sort(v);
}
namespace Alex {
concept_map Foo<fast_vector> { };
}
void sort() {
John::fast_vector v;
Alex::super_sort(v);
}
Zack
int main() {
Fred::sort();
Suzy::sort();
}
Jeremy Siek
72 / 78
namespace AdditiveMonoid {
concept map Monoid<int> {
int binary op(int x, int y) { return x + y; }
int identity elt() { return 0; }
};
}
namespace MultiplicativeMonoid {
concept map Monoid<int> {
int binary op(int x, int y) { return x y; }
int identity elt() { return 1; }
};
}
int main() {
vector<int> v;
{ using namespace AdditiveMonoid; cout << foldl(v.begin(), v.end()); }
{ using namespace MultiplicativeMonoid; cout << foldl(v.begin(), v.end()); }
}
Jeremy Siek
73 / 78
Jeremy Siek
74 / 78
Jeremy Siek
75 / 78
Jeremy Siek
76 / 78
Whats Next?
Jeremy Siek
77 / 78
Hope [1980]
Burstall, MacQueen, Sannella
Scratchpad [1981]
Jenks, Trager
Tecton [1981]
Kapur, Musser, Stepanov
Modules for Standard ML [1984]
MacQueen
C# Generics [2001]
Kennedy, Syme
Jeremy Siek
78 / 78