flexibility versus performance j. daniel garcia · static versus dynamic polymorphism who am i? a...
TRANSCRIPT
Static versus dynamic polymorphism
Static versus dynamic polymorphismFlexibility versus performance
J. Daniel Garcia
ARCOS GroupUniversity Carlos III of Madrid
Spain
December 2, 2016
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 1/97
Static versus dynamic polymorphism
Warning
c This work is under Attribution-NonCommercial-NoDerivatives 4.0 International (CC BY-NC-ND 4.0)license.You are free to Share — copy and redistribute the ma-terial in any medium or format.
b You must give appropriate credit, provide a link to thelicense, and indicate if changes were made. You maydo so in any reasonable manner, but not in any way thatsuggests the licensor endorses you or your use.
e You may not use the material for commercial purposes.d If you remix, transform, or build upon the material, you
may not distribute the modified material.
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 2/97
Static versus dynamic polymorphism
Who am I?
A C++ programmer.Started writing C++ code in 1989.
A university professor in Computer Architecture.
A ISO C++ language standards committee member.
My goal: Improve applications programming.Performance → faster applications.Energy efficiency → better performance per Watt.Maintainability → easier to modify.
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 3/97
Static versus dynamic polymorphism
Who am I?
A C++ programmer.Started writing C++ code in 1989.
A university professor in Computer Architecture.
A ISO C++ language standards committee member.
My goal: Improve applications programming.Performance → faster applications.Energy efficiency → better performance per Watt.Maintainability → easier to modify.
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 3/97
Static versus dynamic polymorphism
Who am I?
A C++ programmer.Started writing C++ code in 1989.
A university professor in Computer Architecture.
A ISO C++ language standards committee member.
My goal: Improve applications programming.Performance → faster applications.Energy efficiency → better performance per Watt.Maintainability → easier to modify.
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 3/97
Static versus dynamic polymorphism
Who am I?
A C++ programmer.Started writing C++ code in 1989.
A university professor in Computer Architecture.
A ISO C++ language standards committee member.
My goal: Improve applications programming.Performance → faster applications.Energy efficiency → better performance per Watt.Maintainability → easier to modify.
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 3/97
Static versus dynamic polymorphism
ARCOS@uc3m
UC3M: A young, international, research oriented university.
ARCOS: Applied research group:Lines: High Performance Computing, Big data,Cyberphisical Systems, and Programming Models forApplication Improvement
Improving Applications:REPARA: Reengineering and Enabling Performance andpoweR of Applications. Funded by EU (FP7).RePhrase: REfactoring Parallel Heterogeneous ResourceAware Applications. Funded by EU (H2020).
Standards:ISO/IEC JTC/SC22/WG21. ISO C++ Committee.
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 4/97
Static versus dynamic polymorphism
Acknowledgments
Some ideas in this talk are highly inspired from SeanParent’s talk Inheritance is base class of evil.
Many thanks to the following individuals for providingfeedback:
Ion Gaztañaga.Manu Sánchez.Joaquín M. López.Bjarne Stroustrup.
Complete code examples can be found at:github.com/jdgarciauc3m/polyexamples.
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 5/97
Static versus dynamic polymorphism
What is this talk about?
Revisit some ideas about classical object orientation.
Remind that polymorphism can be either static ordynamic.
Introduce type erasure as a way to simplify interfaces.
Improvements through small object optimization toreduce allocations and improve performance.
Illustrate both techniques with a canonical simpleexample.
Including performance evaluation.
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 6/97
Static versus dynamic polymorphism
Introduction
1 Introduction
2 Some observations
3 Problem
4 Simple solution
5 Heterogeneous solution
6 Combining polymorphisms: Type Erasure
7 Optimizing small objects
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 7/97
Static versus dynamic polymorphism
Introduction
Tools and problems
A hammer is a wonderful tool for driving a nail
What about nuts?What about screws?What about debugging programs?
Is Object Orientation the programmer’s hammer?
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 8/97
Static versus dynamic polymorphism
Introduction
Tools and problems
A hammer is a wonderful tool for driving a nailWhat about nuts?
What about screws?What about debugging programs?
Is Object Orientation the programmer’s hammer?
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 8/97
Static versus dynamic polymorphism
Introduction
Tools and problems
A hammer is a wonderful tool for driving a nailWhat about nuts?What about screws?
What about debugging programs?
Is Object Orientation the programmer’s hammer?
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 8/97
Static versus dynamic polymorphism
Introduction
Tools and problems
A hammer is a wonderful tool for driving a nailWhat about nuts?What about screws?What about debugging programs?
Is Object Orientation the programmer’s hammer?
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 8/97
Static versus dynamic polymorphism
Introduction
Tools and problems
A hammer is a wonderful tool for driving a nailWhat about nuts?What about screws?What about debugging programs?
Is Object Orientation the programmer’s hammer?
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 8/97
Static versus dynamic polymorphism
Introduction
Origins
Subroutine:David Wheeler and Maurice Wilkes. 1951.
Functional Programming:Lisp, Johh McCarthy. 1958.
Object Oriented ProgrammingSimula, Simula-67. Ole-Johan Dahl and Kristen Nygaard.1960-1970.Smalltalk, Smalltalk-80. Alan C. Kay. 1970-1980.. . .
Generic Programming:CLU. Barbara Liskov. 1974.Ada. Jean Ichbiah. 1983.C++. Bjarne Stroustrup. 1983. STL. Alexander Stepanov.1998.
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 9/97
Static versus dynamic polymorphism
Introduction
Origins
Subroutine:David Wheeler and Maurice Wilkes. 1951.
Functional Programming:Lisp, Johh McCarthy. 1958.
Object Oriented ProgrammingSimula, Simula-67. Ole-Johan Dahl and Kristen Nygaard.1960-1970.Smalltalk, Smalltalk-80. Alan C. Kay. 1970-1980.. . .
Generic Programming:CLU. Barbara Liskov. 1974.Ada. Jean Ichbiah. 1983.C++. Bjarne Stroustrup. 1983. STL. Alexander Stepanov.1998.
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 9/97
Static versus dynamic polymorphism
Introduction
Origins
Subroutine:David Wheeler and Maurice Wilkes. 1951.
Functional Programming:Lisp, Johh McCarthy. 1958.
Object Oriented ProgrammingSimula, Simula-67. Ole-Johan Dahl and Kristen Nygaard.1960-1970.Smalltalk, Smalltalk-80. Alan C. Kay. 1970-1980.. . .
Generic Programming:CLU. Barbara Liskov. 1974.Ada. Jean Ichbiah. 1983.C++. Bjarne Stroustrup. 1983. STL. Alexander Stepanov.1998.
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 9/97
Static versus dynamic polymorphism
Introduction
Origins
Subroutine:David Wheeler and Maurice Wilkes. 1951.
Functional Programming:Lisp, Johh McCarthy. 1958.
Object Oriented ProgrammingSimula, Simula-67. Ole-Johan Dahl and Kristen Nygaard.1960-1970.Smalltalk, Smalltalk-80. Alan C. Kay. 1970-1980.. . .
Generic Programming:CLU. Barbara Liskov. 1974.Ada. Jean Ichbiah. 1983.C++. Bjarne Stroustrup. 1983. STL. Alexander Stepanov.1998.
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 9/97
Static versus dynamic polymorphism
Introduction
But, when did they become popular?
1979-1983: C++.1986: Object Pascal.1986: Eiffel.1995: Java.1995: Ada95.2000: C#.
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 10/97
Static versus dynamic polymorphism
Introduction
Did anything else happen in the 90’s?
Before 2005: Welived in DisneylandAfter 2005: Hit byreality.
Graphic: The free lunch is overHerb Sutter.http://www.gotw.ca/publications/concurrency-ddj.htm
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 11/97
Static versus dynamic polymorphism
Some observations
1 Introduction
2 Some observations
3 Problem
4 Simple solution
5 Heterogeneous solution
6 Combining polymorphisms: Type Erasure
7 Optimizing small objects
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 12/97
Static versus dynamic polymorphism
Some observations
Object orientation
Can we get OO development without OO languages?
Theoretically: YES.Also true in practice:
Old examples: X-Window System, OSF/Motif.
However: Too complicated and error prone.Easy to make mistakes.Don’t leave up to programmers what compilers can dobetter.
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 13/97
Static versus dynamic polymorphism
Some observations
Object orientation
Can we get OO development without OO languages?Theoretically: YES.
Also true in practice:Old examples: X-Window System, OSF/Motif.
However: Too complicated and error prone.Easy to make mistakes.Don’t leave up to programmers what compilers can dobetter.
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 13/97
Static versus dynamic polymorphism
Some observations
Object orientation
Can we get OO development without OO languages?Theoretically: YES.Also true in practice:
Old examples: X-Window System, OSF/Motif.
However: Too complicated and error prone.Easy to make mistakes.Don’t leave up to programmers what compilers can dobetter.
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 13/97
Static versus dynamic polymorphism
Some observations
Object orientation
Can we get OO development without OO languages?Theoretically: YES.Also true in practice:
Old examples: X-Window System, OSF/Motif.
However: Too complicated and error prone.Easy to make mistakes.Don’t leave up to programmers what compilers can dobetter.
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 13/97
Static versus dynamic polymorphism
Some observations
Sometimes we forget
Principles on X-Window design (Bob Scheifler and JimGettys, 1984).
Do not add new functionality unless an implementor cannotcomplete a real application without it.It is as important to decide what a system is not as todecide what it is. Do not serve all the world’s needs.The only thing worse than generalizing from one example isgeneralizing from no examples at all.If a problem is not completely understood, it is probablybest to provide no solution at all.If you can get 90 percent of the desired effect for 10 percentof the work, use the simpler solution.Isolate complexity as much as possible.Provide mechanism rather than policy.
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 14/97
Static versus dynamic polymorphism
Some observations
Everything should be a “method”
Why do we use classes?
Information hiding principle. David Parnas (1972).Increment flexibility and comprehension.Reduce development time.Reduce global coupling.
But ...We assumed that a module or component is mapped to aclass.And we insist in hiding . . .
Even when nothing needs to be hidden.
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 15/97
Static versus dynamic polymorphism
Some observations
Everything should be a “method”
Why do we use classes?Information hiding principle. David Parnas (1972).
Increment flexibility and comprehension.Reduce development time.Reduce global coupling.
But ...We assumed that a module or component is mapped to aclass.And we insist in hiding . . .
Even when nothing needs to be hidden.
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 15/97
Static versus dynamic polymorphism
Some observations
Everything should be a “method”
Why do we use classes?Information hiding principle. David Parnas (1972).
Increment flexibility and comprehension.Reduce development time.Reduce global coupling.
But ...We assumed that a module or component is mapped to aclass.
And we insist in hiding . . .Even when nothing needs to be hidden.
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 15/97
Static versus dynamic polymorphism
Some observations
Everything should be a “method”
Why do we use classes?Information hiding principle. David Parnas (1972).
Increment flexibility and comprehension.Reduce development time.Reduce global coupling.
But ...We assumed that a module or component is mapped to aclass.And we insist in hiding . . .
Even when nothing needs to be hidden.
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 15/97
Static versus dynamic polymorphism
Some observations
Everything should be a “method”
Why do we use classes?Information hiding principle. David Parnas (1972).
Increment flexibility and comprehension.Reduce development time.Reduce global coupling.
But ...We assumed that a module or component is mapped to aclass.And we insist in hiding . . .
Even when nothing needs to be hidden.
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 15/97
Static versus dynamic polymorphism
Some observations
Class “methods”
A method from the metaclass → Shared by all instances.What is this thing?
Java
public final class Math {public static double abs(double a) {/∗...∗/}
}
// Invocationx = Math.abs(y);
C++
namespace std {double abs(double arg);
}
// Invocation
x = abs(y);
We tend to invent classes:I just need to put this in some class!
Or invent animals like Integer.Or contort main to become a method.
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 16/97
Static versus dynamic polymorphism
Some observations
Class “methods”
A method from the metaclass → Shared by all instances.What is this thing?
Java
public final class Math {public static double abs(double a) {/∗...∗/}
}
// Invocationx = Math.abs(y);
C++
namespace std {double abs(double arg);
}
// Invocation
x = abs(y);
We tend to invent classes:I just need to put this in some class!
Or invent animals like Integer.Or contort main to become a method.
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 16/97
Static versus dynamic polymorphism
Some observations
Class “methods”
A method from the metaclass → Shared by all instances.What is this thing?
Java
public final class Math {public static double abs(double a) {/∗...∗/}
}
// Invocationx = Math.abs(y);
C++
namespace std {double abs(double arg);
}
// Invocation
x = abs(y);
We tend to invent classes:I just need to put this in some class!
Or invent animals like Integer.Or contort main to become a method.
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 16/97
Static versus dynamic polymorphism
Some observations
Class “methods”
A method from the metaclass → Shared by all instances.What is this thing?
Java
public final class Math {public static double abs(double a) {/∗...∗/}
}
// Invocationx = Math.abs(y);
C++
namespace std {double abs(double arg);
}
// Invocation
x = abs(y);
We tend to invent classes:I just need to put this in some class!
Or invent animals like Integer.Or contort main to become a method.
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 16/97
Static versus dynamic polymorphism
Some observations
Class “methods”
A method from the metaclass → Shared by all instances.What is this thing?
Java
public final class Math {public static double abs(double a) {/∗...∗/}
}
// Invocationx = Math.abs(y);
C++
namespace std {double abs(double arg);
}
// Invocation
x = abs(y);
We tend to invent classes:I just need to put this in some class!
Or invent animals like Integer.
Or contort main to become a method.
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 16/97
Static versus dynamic polymorphism
Some observations
Class “methods”
A method from the metaclass → Shared by all instances.What is this thing?
Java
public final class Math {public static double abs(double a) {/∗...∗/}
}
// Invocationx = Math.abs(y);
C++
namespace std {double abs(double arg);
}
// Invocation
x = abs(y);
We tend to invent classes:I just need to put this in some class!
Or invent animals like Integer.Or contort main to become a method.
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 16/97
Static versus dynamic polymorphism
Some observations
Paranoid information hiding
Attributes in a class must always be private.
And then we fill up everything with getters and setters.Where is information hiding then?
A key-value entry
class entry {public:
entry( int k, const string & v);void set_key(int k) { key_=k; }int get_key() const { return key_; }void set_value(const string & v) { value_=v; }string get_value() const { return value_; }
private:int key_;string value_;
};
Or a key-value entry
struct entry {entry( int k, const string & v);int key;string value;
};
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 17/97
Static versus dynamic polymorphism
Some observations
Paranoid information hiding
Attributes in a class must always be private.And then we fill up everything with getters and setters.
Where is information hiding then?
A key-value entry
class entry {public:
entry( int k, const string & v);void set_key(int k) { key_=k; }int get_key() const { return key_; }void set_value(const string & v) { value_=v; }string get_value() const { return value_; }
private:int key_;string value_;
};
Or a key-value entry
struct entry {entry( int k, const string & v);int key;string value;
};
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 17/97
Static versus dynamic polymorphism
Some observations
Paranoid information hiding
Attributes in a class must always be private.And then we fill up everything with getters and setters.Where is information hiding then?
A key-value entry
class entry {public:
entry( int k, const string & v);void set_key(int k) { key_=k; }int get_key() const { return key_; }void set_value(const string & v) { value_=v; }string get_value() const { return value_; }
private:int key_;string value_;
};
Or a key-value entry
struct entry {entry( int k, const string & v);int key;string value;
};
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 17/97
Static versus dynamic polymorphism
Some observations
Paranoid information hiding
Attributes in a class must always be private.And then we fill up everything with getters and setters.Where is information hiding then?
A key-value entry
class entry {public:
entry( int k, const string & v);void set_key(int k) { key_=k; }int get_key() const { return key_; }void set_value(const string & v) { value_=v; }string get_value() const { return value_; }
private:int key_;string value_;
};
Or a key-value entry
struct entry {entry( int k, const string & v);int key;string value;
};
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 17/97
Static versus dynamic polymorphism
Some observations
Paranoid information hiding
Attributes in a class must always be private.And then we fill up everything with getters and setters.Where is information hiding then?
A key-value entry
class entry {public:
entry( int k, const string & v);void set_key(int k) { key_=k; }int get_key() const { return key_; }void set_value(const string & v) { value_=v; }string get_value() const { return value_; }
private:int key_;string value_;
};
Or a key-value entry
struct entry {entry( int k, const string & v);int key;string value;
};
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 17/97
Static versus dynamic polymorphism
Some observations
Inheritance
Inheritance: Code reuse mechanism.Interface inheritance (Subtyping): Establishes an is-arelationship.Implementation inheritance: Implementation reusemechanism.
Approaches:All classes must be organized in a single universalhierarchy.
A Vector extends an AbstractList which extends anAbstractCollection which extend an Object.
Limited use of inheritance and only if really needed.A std::vector does not inherit from any other class.
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 18/97
Static versus dynamic polymorphism
Some observations
Inheritance
Inheritance: Code reuse mechanism.Interface inheritance (Subtyping): Establishes an is-arelationship.Implementation inheritance: Implementation reusemechanism.
Approaches:All classes must be organized in a single universalhierarchy.
A Vector extends an AbstractList which extends anAbstractCollection which extend an Object.
Limited use of inheritance and only if really needed.A std::vector does not inherit from any other class.
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 18/97
Static versus dynamic polymorphism
Some observations
Polymorphism
Polymorphism: Ability to offer the same interface withvarying implementations.
Usually a synonym for dynamic polymorphism.
Dynamic Polymorphism: Implementation selection takenat run-time (late binding).
Small overhead per function invocation.Acceptable when limited use.However additional cost derived from allocation and heapfragmentation.
Sometimes leading to designs more flexible than reallyneeded.
Just in case some day . . .
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 19/97
Static versus dynamic polymorphism
Some observations
Polymorphism
Polymorphism: Ability to offer the same interface withvarying implementations.Usually a synonym for dynamic polymorphism.
Dynamic Polymorphism: Implementation selection takenat run-time (late binding).
Small overhead per function invocation.Acceptable when limited use.However additional cost derived from allocation and heapfragmentation.
Sometimes leading to designs more flexible than reallyneeded.
Just in case some day . . .
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 19/97
Static versus dynamic polymorphism
Some observations
Polymorphism
Polymorphism: Ability to offer the same interface withvarying implementations.Usually a synonym for dynamic polymorphism.
Dynamic Polymorphism: Implementation selection takenat run-time (late binding).
Small overhead per function invocation.Acceptable when limited use.However additional cost derived from allocation and heapfragmentation.
Sometimes leading to designs more flexible than reallyneeded.
Just in case some day . . .
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 19/97
Static versus dynamic polymorphism
Some observations
There is another polymorphism
Static polymorphism: Implementation selection taken atcompile-time (early binding).
It is not always possible.Enough flexibility in many situations.No run-time overhead.
Generic sort
template <typename C>void sort(C & c) {
sort (c.begin() , c.end()) ;}
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 20/97
Static versus dynamic polymorphism
Some observations
An additional problem
Resource management.Many OO languages have taken the choice of makingprogrammers life easy by means of garbage collection.
But we still have memory leaks everywhere.
Garbage collection.Generally has impact on performance.Increases impact due to the multi-core revolution.The best garbage collection strategy is not to generategarbage.
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 21/97
Static versus dynamic polymorphism
Some observations
An additional problem
Resource management.Many OO languages have taken the choice of makingprogrammers life easy by means of garbage collection.
But we still have memory leaks everywhere.
Garbage collection.Generally has impact on performance.Increases impact due to the multi-core revolution.The best garbage collection strategy is not to generategarbage.
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 21/97
Static versus dynamic polymorphism
Some observations
An additional problem
Resource management.Many OO languages have taken the choice of makingprogrammers life easy by means of garbage collection.
But we still have memory leaks everywhere.
Garbage collection.Generally has impact on performance.Increases impact due to the multi-core revolution.The best garbage collection strategy is not to generategarbage.
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 21/97
Static versus dynamic polymorphism
Problem
1 Introduction
2 Some observations
3 Problem
4 Simple solution
5 Heterogeneous solution
6 Combining polymorphisms: Type Erasure
7 Optimizing small objects
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 22/97
Static versus dynamic polymorphism
Problem
Vector graphics
We want to represent a graphic scene with a collection ofgeometric shapes (rectangles, circles, . . . ).
All objects have a position (x,y).For simplicity we use integer coordinates.
Operations on a scene:Load from file.Store to file.Compute sum of all areas.Translate all objects (given a translation offset).Enlarge objects (given a factor).
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 23/97
Static versus dynamic polymorphism
Problem
Some utilities to consider
Generate a file with random shapes.Determine the addition of all shapes in a file.Translate all shapes in a file.Enlarge all objects in a file.
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 24/97
Static versus dynamic polymorphism
Simple solution
1 Introduction
2 Some observations
3 Problem
4 Simple solution
5 Heterogeneous solution
6 Combining polymorphisms: Type Erasure
7 Optimizing small objects
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 25/97
Static versus dynamic polymorphism
Simple solution
Minimal solution
Consider that the only possible shape the rectangle.All shapes are rectangles.Position (x,y).Size (width,height).
Simplified code:A single class (rectangle).Scene contains a vector<rectangle>.
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 26/97
Static versus dynamic polymorphism
Simple solution
File format
scenerectangle: 37 29 7 10rectangle: 73 100 4 5rectangle: 31 75 9 2rectangle: 84 28 7 3rectangle: 5 63 2 6end-scene
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 27/97
Static versus dynamic polymorphism
Simple solution
A rectangle
rectangle.h
class rectangle {public:
rectangle() noexcept = default;
rectangle( int x, int y, int w, int h) noexcept :x_{x}, y_{y}, width_{w}, height_{h} {}
int area() const noexcept{ return width_ ∗ height_; }
void translate ( int dx, int dy) noexcept{ x_ += dx; y_ += dy; }
void enlarge(int k) noexcept{ width_ ∗= k; height_ ∗= k; }
// ...cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 28/97
Static versus dynamic polymorphism
Simple solution
A rectangle
rectangle.h
// ...
friend std :: ostream & operator<<(std::ostream & os, const rectangle & r);friend std :: istream & operator>>(std::istream & is, rectangle & r) ;
private:int x_=0;int y_=0;int width_=0;int height_=0;
};
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 29/97
Static versus dynamic polymorphism
Simple solution
Rectangles I/O
rectangle.cpp
std :: ostream & operator<<(std::ostream & os, const rectangle & r) {return os << r.x_ << " " << r.y_ << " "
<< r.width_ << " " << r.height_;}
std :: istream & operator>>(std::istream & is, rectangle & r) {return is >> r.x_ >> r.y_
>> r.width_ >> r.height_;}
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 30/97
Static versus dynamic polymorphism
Simple solution
A scene
scene.h
class rectangle;
class scene {public:
void add_shape(const rectangle & r);int size () const noexcept { return shapes_.size(); }
long long area() const noexcept;void translate ( int dx, int dy) noexcept;void enlarge(int k) noexcept;
friend std :: ostream & operator<<(std::ostream & os, const scene & s);friend std :: istream & operator>>(std::istream & is, scene & s);
private:std :: vector<rectangle> shapes_;
};
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 31/97
Static versus dynamic polymorphism
Simple solution
Implementing a scene
scene.cpp
void scene::add_shape(const rectangle & r) {shapes_.push_back(r);
}
long long scene::area() const noexcept {// transform_reduce(begin(shapes_), end(shapes_).// []( auto x) { return x.area() ; }// []( auto x, auto y) { return x+y; }) ;long long r = 0;for (auto && s : shapes_) {
r += s.area() ;}return r ;
}
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 32/97
Static versus dynamic polymorphism
Simple solution
Implementing a scene
scene.cpp
void scene::translate( int dx, int dy) noexcept {for (auto && s : shapes_) {
s. translate (dx,dy);}
}
void scene::enlarge(int k) noexcept {for (auto && s : shapes_) {
s.enlarge(k);}
}
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 33/97
Static versus dynamic polymorphism
Simple solution
Dumping a scene
scene.cpp
std :: ostream & operator<<(std::ostream & os, const scene & s) {os << "scene\n";for (auto && s : s.shapes_) {
os << "rectangle: " << s << std ::endl;}os << "end−scene";return os;
}
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 34/97
Static versus dynamic polymorphism
Simple solution
Reading a scene
scene.cpp
std :: istream & operator>>(std::istream & is, scene & s) {using namespace std;string w;is >> w;if (w!="scene") return is;while ( is >> w) {
if (w=="rectangle:") {rectangle r ;is >> r;s.add_shape(r);
}else if (w=="end−scene") {
return is ;}else {
is . setstate(ios_base:: failbit ) ;return is ;
}}return is ;
}
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 35/97
Static versus dynamic polymorphism
Simple solution
Generating scenes
genscene.cpp
void generate_scene(const std::string & name, int n) {using namespace std;using namespace dsl;
cout << "Writing file " << name << endl;cout << "sizeof(rectangle)= " << sizeof(dsl :: rectangle) << endl;cout << "Generating " << n << " elements\n";
random_device rd;scene s;for ( int i=0; i<n; i++) {
auto r = random_rectangle(rd);s.add_shape(r);
}
ofstream of{name};of << s << endl;if (! of) throw runtime_error{"Cannot write to file : " + name};
cout << "Generated file " << name << " with " << n << " elements\n";}
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 36/97
Static versus dynamic polymorphism
Simple solution
Computing areas
area.cpp
void print_area(const std:: string & inname) {using namespace std;using namespace dsl;
scene s;ifstream in{inname};in >> s;if (! in ) throw runtime_error{"Error reading scene file " };
cout << s.area() << endl;}
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 37/97
Static versus dynamic polymorphism
Simple solution
Translating shapes
translate.cpp
void translate_scene(const std::string & inname, const std::string & outname,int dx, int dy) {
using namespace std;using namespace dsl;
cout << "Reading gfile " << inname << endl;
scene s;ifstream in{inname};in >> s;if (! in ) throw runtime_error{"Error reading scene file : " + inname};
s. translate (dx,dy);
ofstream out{outname};out << s;if (! out) throw runtime_error{"Error writing scene file " + outname};
cout << s.size () << " shapes written to file " << outname << endl;}
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 38/97
Static versus dynamic polymorphism
Heterogeneous solution
1 Introduction
2 Some observations
3 Problem
4 Simple solution
5 Heterogeneous solution
6 Combining polymorphisms: Type Erasure
7 Optimizing small objects
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 39/97
Static versus dynamic polymorphism
Heterogeneous solution
Shapes may be different
Multiple types for shapes.We will restrict our example to rectangle and circle.After all this is a textbook example :-)
Classical solution:A base class: shape.One derived class per shape kind: rectangle, circle.Scene keeps a list of shapes.
We cannot store objects from different types/sizes in acontainer.We store (smart) pointers to shapes.We use std::shared_ptr to simplify memory management:
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 40/97
Static versus dynamic polymorphism
Heterogeneous solution
Designing the base class
Construction and destruction:Destructor needs to be virtual.We need to explicitly define the empty constructor.
shape.h
class shape {public:
shape() noexcept = default;virtual ~shape() noexcept = default;
shape(int x, int y) noexcept :x_{x}, y_{y} {}
private:int x_=0;int y_=0;
};
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 41/97
Static versus dynamic polymorphism
Heterogeneous solution
Designing the base class
Position remains in the shape.Translation is managed here.Pure virtual functions to be refined in derived classes.
shape.h
// ...
void translate ( int dx, int dy) noexcept{ x_ += dx; y_ += dy; }
virtual int area() const noexcept = 0;virtual void enlarge(int k) noexcept = 0;
// ...
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 42/97
Static versus dynamic polymorphism
Heterogeneous solution
I/O
Insertion and extraction operators need to be virtualized.An operator and a pure virtual function.A function to obtain the text tag with the object type.
rectangle, circle.
shape.h
// ...
virtual std :: string tagname() const = 0;
friend std :: ostream & operator<<(std::ostream & os, const shape & r);virtual std :: ostream & insert(std :: ostream & os) const;
friend std :: istream & operator>>(std::istream & is, shape & r);virtual std :: istream & extract (std :: istream & is ) ;
// ...
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 43/97
Static versus dynamic polymorphism
Heterogeneous solution
I/O
shape.cpp
std :: ostream & shape::insert(std ::ostream & os) const {return os << x_ << ’ ’ << y_ << ’ ’ ;
}
std :: istream & shape::extract(std :: istream & is ) {return is >> x_ >> y_;
}
std :: ostream & operator<<(std::ostream & os, const shape & r) {return r . insert (os);
}
std :: istream & operator>>(std::istream & is, shape & r) {return r . extract ( is ) ;
}
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 44/97
Static versus dynamic polymorphism
Heterogeneous solution
Deriving the rectangle
rectangle.h
class rectangle final : public shape {public:
rectangle() noexcept = default;
rectangle( int x, int y, int w, int h) :shape{x,y}, width_{w}, height_{h} {}
int area() const noexcept override{ return width_ ∗ height_; }
void enlarge(int k) noexcept override{ width_ ∗= k; height_ ∗= k; }
private:int width_=0;int height_=0;
};cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 45/97
Static versus dynamic polymorphism
Heterogeneous solution
Deriving the rectangle
rectangle.h
std :: string tagname() const override{ return "rectangle"; }
friend std :: ostream & operator<<(std::ostream & os, const rectangle & r);std :: ostream & insert(std :: ostream & os) const override;
friend std :: istream & operator>>(std::istream & is, rectangle & r) ;std :: istream & extract (std :: istream & is ) override;
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 46/97
Static versus dynamic polymorphism
Heterogeneous solution
Rectangle I/O
rectangle.cpp
std :: ostream & operator<<(std::ostream & os, const rectangle & r) {return r . insert (os);
}
std :: ostream & rectangle::insert (std :: ostream & os) const {shape::insert(os);return os << width_ << " " << height_;
}
std :: istream & operator>>(std::istream & is, rectangle & r) {return r . extract ( is ) ;
}
std :: istream & rectangle :: extract (std :: istream & is ) {shape::extract( is ) ;return is >> width_ >> height_;
}cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 47/97
Static versus dynamic polymorphism
Heterogeneous solution
Designing the scene
Polymorphic storage of shapes.Shapes are kept in a vector of pointers to the base class(shape).We use shared_ptr to get proper memory management.
Interface for adding shapes to a scene.Function add_shape() now takes an argumentshared_ptr<shape>.Argument taken as r-value reference.
It allows to take advantage of move semantics.
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 48/97
Static versus dynamic polymorphism
Heterogeneous solution
A scene with polymorphic shapes
scene.hclass shape;
class scene {public:
void add_shape(std::shared_ptr<shape> && s) {shapes_.push_back(std::forward<std::shared_ptr<shape>>(s));
}int size () const noexcept { return shapes_.size(); }
long long area() const noexcept;void translate ( int dx, int dy) noexcept;void enlarge(int k) noexcept;
friend std :: ostream & operator<<(std::ostream & os, const scene & s);friend std :: istream & operator>>(std::istream & is, scene & s);
private:std :: vector<std ::shared_ptr<shape>> shapes_;
};
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 49/97
Static versus dynamic polymorphism
Heterogeneous solution
Implementing scenes
scene.cpp
long long scene::area() const noexcept {long long r = 0;for (auto && s : shapes_) {
r += s−>area();}return r ;
}
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 50/97
Static versus dynamic polymorphism
Heterogeneous solution
Implementing scenes
scene.cpp
void scene::translate( int dx, int dy) noexcept {for (auto && s : shapes_) {
s−>translate(dx,dy);}
}
void scene::enlarge(int k) noexcept {for (auto && s : shapes_) {
s−>enlarge(k);}
}
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 51/97
Static versus dynamic polymorphism
Heterogeneous solution
Writing scenes
scene.cpp
std :: ostream & operator<<(std::ostream & os, const scene & s) {os << "scene\n";for (auto && s : s.shapes_) {
os << s−>tagname() << ": ";s−>insert(os); // Polymorphic writeos << std ::endl;
}os << "end−scene";return os;
}
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 52/97
Static versus dynamic polymorphism
Heterogeneous solution
A shape factory
scene.cpp
namespace { // Anonymous namespace
std :: shared_ptr<shape> make_shape(const std::string & cname) {using namespace std;shared_ptr<shape> p = nullptr;if (cname=="rectangle:") p = make_shared<rectangle>();else if (cname=="circle:") p = make_shared<circle>();return p;
}
}
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 53/97
Static versus dynamic polymorphism
Heterogeneous solution
Reading shapes
scene.cpp
std :: istream & operator>>(std::istream & is, scene & s) {using namespace std;string w;is >> w;if (w!="scene") return is;while ( is >> w) {
auto sh = make_shape(w);if (sh) {
is >> ∗sh;s.add_shape(std::move(sh));
}else if (w=="end−scene") {
return is ;}else {
is . setstate(ios_base:: failbit ) ;return is ;
}}return is ;
}
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 54/97
Static versus dynamic polymorphism
Heterogeneous solution
Using the scenes
Changing the interface:Function add_shape() changed its interface.
Effects on code:Complexity transferred to shape developer.Objects created in dynamic memory need to be transferred.
Effects on performance:Dynamic memory higher use.
One allocation per shape.Worse processors cache behaviour.
Shapes are no longer contiguous in memory.
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 55/97
Static versus dynamic polymorphism
Combining polymorphisms: Type Erasure
1 Introduction
2 Some observations
3 Problem
4 Simple solution
5 Heterogeneous solution
6 Combining polymorphisms: Type Erasure
7 Optimizing small objects
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 56/97
Static versus dynamic polymorphism
Combining polymorphisms: Type Erasure
Dynamic versus static polymorphism
Dynamic polymorphism:Provides extra flexibility.Requires to incorporate new classes into a class hierarchy.Exhibits higher run time cost.
Static polymorphism:Lower flexibility (although enough in many occasions).Used types may be completely unrelated.Lower run-time cost.
Virtue is the golden mean between two extremes(Aristotle).
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 57/97
Static versus dynamic polymorphism
Combining polymorphisms: Type Erasure
Dynamic versus static polymorphism
Dynamic polymorphism:Provides extra flexibility.Requires to incorporate new classes into a class hierarchy.Exhibits higher run time cost.
Static polymorphism:Lower flexibility (although enough in many occasions).Used types may be completely unrelated.Lower run-time cost.
Virtue is the golden mean between two extremes(Aristotle).
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 57/97
Static versus dynamic polymorphism
Combining polymorphisms: Type Erasure
Dynamic versus static polymorphism
Dynamic polymorphism:Provides extra flexibility.Requires to incorporate new classes into a class hierarchy.Exhibits higher run time cost.
Static polymorphism:Lower flexibility (although enough in many occasions).Used types may be completely unrelated.Lower run-time cost.
Virtue is the golden mean between two extremes(Aristotle).
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 57/97
Static versus dynamic polymorphism
Combining polymorphisms: Type Erasure
Hiding polymorphism
Hide polymorphism behind a single class.Allows using completely unrelated.Hides inheritance as an implementation mechanism.
Shapes design:A generic constructor taking values from any type.A factory function for empty values.Class is move constructible but not copyable.Class hierarchy becomes an implementation private detail.A pointer to base class may hold a derived object.
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 58/97
Static versus dynamic polymorphism
Combining polymorphisms: Type Erasure
A generic constructor
A generic class . . .
template <typename T>class A {public:
A(T x);// ...
};
Each instantiation leadsto a different class.
Types A<int> andA<long> are different.
. . . different from generic constructor
class A {public:
template <typename T>A(T x);// ...
};
All instantiation lead tothe same type.
Both A{x} y A{y} havetype A.
Even if x and y havedifferent types.
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 59/97
Static versus dynamic polymorphism
Combining polymorphisms: Type Erasure
A generic constructor
A generic class . . .
template <typename T>class A {public:
A(T x);// ...
};
Each instantiation leadsto a different class.
Types A<int> andA<long> are different.
. . . different from generic constructor
class A {public:
template <typename T>A(T x);// ...
};
All instantiation lead tothe same type.
Both A{x} y A{y} havetype A.
Even if x and y havedifferent types.
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 59/97
Static versus dynamic polymorphism
Combining polymorphisms: Type Erasure
What is type erasure about?
A technique to allow a concrete type to hold values fromdifferent unrelated types.
Accept values from multiple types in constructor.Define wrapper classes for each of those types.Define a single base class for all wrappers.Hold a pointer to the single base classe.Delegate operations to wrappers through base classinterface.
The accepted unrelated types are erased as they are nolonger visible.
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 60/97
Static versus dynamic polymorphism
Combining polymorphisms: Type Erasure
Erasing types
Hierarchy
class wrapper_base {// ...string to_string () const;
};
class wrapper_int : public wrapper_base {// ...string to_string () const;
private:int value;
};
class wrapper_double : public wrapper_base {// ...string to_string () const;
private:double value;
};
Valueclass value {public:
value(int x) :wrapper{make_unique<wrapper_int>(x)} {}
value(double x) :wrapper{make_unique<wrapper_double>(x)} {}
string to_string () const { wrapper_−>to_string(); }
private:unique_ptr<wrapper_base> wrapper_;
};
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 61/97
Static versus dynamic polymorphism
Combining polymorphisms: Type Erasure
A private hierarchy
Hierarcy for shape
class shape {public:
template <typename T> shape(T x);
private:class shape_base { /∗...∗/ };
template <typename T>class concrete_shape : public shape_base {
// ...private:
T impl_;};
std :: unique_ptr<shape_base> self_;};
self_ pointer holds anobject from any derivedclass.
Class shape_base mayhave pure virtualfunctions.
Virtual function redefinedin class concrete_shape.
Class concrete_shapemay delegate to objectimplementation impl_.
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 62/97
Static versus dynamic polymorphism
Combining polymorphisms: Type Erasure
A polymorphic factory function
Factory function
class shape {// ...template <typename T>friend shape make_shape();// ...
};
template <typename T>shape make_shape() {
shape s;s. self_ = make_unique<
shape::concrete_shape<T>>();return s;
}
Can’t have a genericempty constructor.Factory function ismade friend to getimplementationaccess.
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 63/97
Static versus dynamic polymorphism
Combining polymorphisms: Type Erasure
A shape with value semantics
shape.h
class shape {public:
shape() : self_ {nullptr} {}
template<typename T>shape(T x);
shape(const shape &) = delete;shape & operator=(const shape &) = delete;
shape(shape &&) noexcept = default;shape & operator=(shape &&) = default;
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 64/97
Static versus dynamic polymorphism
Combining polymorphisms: Type Erasure
A shape with value semantics
shape.h
std :: string tagname() const { return self_−>tagname(); }int area() const { return self_−>area(); }void translate ( int dx, int dy) { self_−>translate(dx,dy); }void enlarge(int k) {self_−>enlarge(k); }
friend std :: ostream & operator<<(std::ostream & os, const shape & s){ s. self_−>insert(os); return os; }
friend std :: istream & operator>>(std::istream & is, const shape & s){ s. self_−>extract(is) ; return is ; }
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 65/97
Static versus dynamic polymorphism
Combining polymorphisms: Type Erasure
A shape with value semantics
shape.h
private:
class shape_base {public:
shape_base() {}virtual ~shape_base() = default;virtual std :: string tagname() const = 0;virtual int area() const = 0;virtual void translate ( int dx, int dy) = 0;virtual void enlarge(int k) = 0;virtual void insert (std :: ostream & os) const = 0;virtual void extract (std :: istream & is ) = 0;
};
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 66/97
Static versus dynamic polymorphism
Combining polymorphisms: Type Erasure
A shape with value semantics
shape.h
template <typename T>class concrete_shape final : public shape_base {public:
concrete_shape() : impl_{} {}concrete_shape(T && x) : impl_{std::forward<T>(x)} {}virtual ~concrete_shape() = default;std :: string tagname() const override { return impl_.tagname(); }int area() const override { return impl_.area(); }void translate ( int dx, int dy) override { impl_. translate (dx,dy); }void enlarge(int k) override {impl_.enlarge(k); }void insert (std :: ostream & os) const override { os << impl_; }void extract (std :: istream & is ) override { is >> impl_; }
private:T impl_;
};
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 67/97
Static versus dynamic polymorphism
Combining polymorphisms: Type Erasure
A shape with value semantics
shape.h
std :: unique_ptr<shape_base> self_;
template <typename U> friend shape make_shape();};
template <typename T>shape::shape(T x) :
self_ {std :: make_unique<concrete_shape<T>>(std::forward<T>(x))}{}
template<typename T>shape make_shape() {
shape s;s. self_ = std :: make_unique<shape::concrete_shape<T>>();return s;
}
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 68/97
Static versus dynamic polymorphism
Combining polymorphisms: Type Erasure
What about concrete classes?
Simplification:They are now classes without dependencies.They do not inherit from any other class.All member functions are now non-virtual.
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 69/97
Static versus dynamic polymorphism
Combining polymorphisms: Type Erasure
What about the scene?
scene.h
class scene {public:
void add_shape(shape && s) { shapes_.push_back(std::forward<shape>(s)); }int size () const { return shapes_.size(); }
long long area() const;void translate ( int dx, int dy);void enlarge(int k) ;
friend std :: ostream & operator<<(std::ostream & os, const scene & s);friend std :: istream & operator>>(std::istream & is, scene & s);
private:std :: vector<shape> shapes_;
};
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 70/97
Static versus dynamic polymorphism
Combining polymorphisms: Type Erasure
And what about client code?
Value semantics is back!
Client code
shape s = make_shape<rectangle>();myscene.add_shape(move(s));// ...
Or even better!
Client code
myscene.add_shape(make_shape<rectangle>());// ...
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 71/97
Static versus dynamic polymorphism
Combining polymorphisms: Type Erasure
And what about client code?
Value semantics is back!
Client code
shape s = make_shape<rectangle>();myscene.add_shape(move(s));// ...
Or even better!
Client code
myscene.add_shape(make_shape<rectangle>());// ...
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 71/97
Static versus dynamic polymorphism
Optimizing small objects
1 Introduction
2 Some observations
3 Problem
4 Simple solution
5 Heterogeneous solution
6 Combining polymorphisms: Type Erasure
7 Optimizing small objects
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 72/97
Static versus dynamic polymorphism
Optimizing small objects
Memory layout and performance
Type erasure based solution simplifies extension butexhibits same performance problems that object orientedversion.
Each object is allocated independently.Many individual memory allocations.Objects are not contiguously allocated.Low processor cache hit rate.
Slightly mitigated by use of make_shared():One allocation per call insted of two.Implicit use of std::allocator.Implementations sometimes use memory pools forstd::allocator.
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 73/97
Static versus dynamic polymorphism
Optimizing small objects
Memory layout and performance
Type erasure based solution simplifies extension butexhibits same performance problems that object orientedversion.
Each object is allocated independently.Many individual memory allocations.Objects are not contiguously allocated.Low processor cache hit rate.
Slightly mitigated by use of make_shared():One allocation per call insted of two.Implicit use of std::allocator.Implementations sometimes use memory pools forstd::allocator.
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 73/97
Static versus dynamic polymorphism
Optimizing small objects
Small object optimization
Use a fixed size buffer for each shape.If the object is very small construct directly in buffer.If object is large construct in buffer a pointer to adynamically allocated object.
Buffer type
constexpr static int size_threshold = 32;
using internal_buffer = char[size_threshold];
We may fix the buffer size to 32 bytes.Enough size for very small objects plus a vptr pointer.A size of 16 allows only extremely small objects.A size of 64 would decrease hit rate.Threshold might be application dependent.
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 74/97
Static versus dynamic polymorphism
Optimizing small objects
Small object optimization
Use a fixed size buffer for each shape.If the object is very small construct directly in buffer.If object is large construct in buffer a pointer to adynamically allocated object.
Buffer type
constexpr static int size_threshold = 32;
using internal_buffer = char[size_threshold];
We may fix the buffer size to 32 bytes.Enough size for very small objects plus a vptr pointer.A size of 16 allows only extremely small objects.A size of 64 would decrease hit rate.Threshold might be application dependent.
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 74/97
Static versus dynamic polymorphism
Optimizing small objects
Class hierarchy
Private classes as implementation detail.
shape_base: Base in hierarchy.Base class with pure virtual functions.Pure virtual function to move construct in a buffer withplacement (placement_move()).
local_shape<S>: Derived wrapper for small objects.Holds a member with shape S.Delegate virtual operations to that member.
dynamic_shape<S>: Derived wrapper for pointer to largeobjects.
Holds a member with pointer to allocated shape S.Delegate virtual operations to the pointed object.
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 75/97
Static versus dynamic polymorphism
Optimizing small objects
private class hierarchy
shape.h
class shape {private:
// ...class shape_base { /∗ ... ∗/ };
template <typename S>class local_shape final : public shape_base { /∗ ... ∗/ };
template <typename S>class dynamic_shape final : public shape_base { /∗ ... ∗/ };
};
However:
We do not keep a pointer to the base.Instead we use a buffer where we store either a local_shape<S>or a dynamic_shape<S>.
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 76/97
Static versus dynamic polymorphism
Optimizing small objects
Defining the buffer
A buffer for objects
class shape {private:
using internal_buffer = char[size_threshold];internal_buffer buffer_ ;
shape_base ∗ self() noexcept {return reinterpret_cast<shape_base∗>(&buffer_);
}// ...
};
Just need to guarantee that every shape always has avalid object derived from shape_base in its buffer_.
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 77/97
Static versus dynamic polymorphism
Optimizing small objects
A base for all shapes
shape.h
class shape_base {public:
shape_base() noexcept {}virtual ~shape_base() noexcept = default;
virtual void placement_move(internal_buffer & buf) noexcept = 0;
virtual std :: string tagname() const = 0;virtual int area() const noexcept = 0;virtual void translate ( int dx, int dy) noexcept = 0;virtual void enlarge(int k) noexcept = 0;virtual std :: ostream & insert(std :: ostream & os) const noexcept = 0;virtual std :: istream & extract (std :: istream & is ) noexcept = 0;
};
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 78/97
Static versus dynamic polymorphism
Optimizing small objects
A local shape
shape.h
template <typename S>class local_shape final : public shape_base {public:
local_shape() noexcept : impl_{} {}local_shape(S && x) noexcept : impl_{std::forward<S>(x)} {}virtual ~local_shape() noexcept = default;
virtual void placement_move(internal_buffer & buf) noexcept override;
std :: string tagname() const override { return impl_.tagname(); }int area() const noexcept override { return impl_.area(); }void translate ( int dx, int dy) noexcept override { impl_.translate(dx,dy); }void enlarge(int k) noexcept override {impl_.enlarge(k); }std :: ostream & insert(std :: ostream & os) const noexcept override { return os << impl_; }std :: istream & extract (std :: istream & is ) noexcept override { return is >> impl_; }
private:S impl_;
};
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 79/97
Static versus dynamic polymorphism
Optimizing small objects
A dynamic shape
shape.h
template <typename S>class dynamic_shape final : public shape_base {public:
dynamic_shape() : impl_{std::make_unique<S>()} {}dynamic_shape(S && s) : impl_{std::make_unique<S>(std::forward<S>(s))} {}dynamic_shape(std::unique_ptr<S> && p) noexcept : impl_{std::forward<std::unique_ptr<S>>(p)} {}virtual ~dynamic_shape() noexcept = default;
virtual void placement_move(internal_buffer & buf) noexcept override;
std :: string tagname() const noexcept override { return impl_−>tagname(); }int area() const noexcept override { return impl_−>area(); }void translate ( int dx, int dy) noexcept override { impl_−>translate(dx,dy); }void enlarge(int k) noexcept override {impl_−>enlarge(k); }std :: ostream & insert(std :: ostream & os) const noexcept override { return os << ∗impl_; }std :: istream & extract (std :: istream & is ) noexcept override { return is >> ∗impl_; }
private:std :: unique_ptr<S> impl_;
};
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 80/97
Static versus dynamic polymorphism
Optimizing small objects
Placement move
Move construct an object into a given buffer.Operation is virtualized.
shape.h
template <typename S>void shape::local_shape<S>::placement_move(internal_buffer & buf) noexcept {
new (&buf) local_shape<S>(std::move(impl_));}
template <typename S>void shape::dynamic_shape<S>::placement_move(internal_buffer & buf) noexcept {
new (&buf) dynamic_shape<S>(std::move(impl_));}
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 81/97
Static versus dynamic polymorphism
Optimizing small objects
Support for concepts-like
shape.h
template <typename T>static constexpr bool is_small() {
return sizeof(local_shape<T>) <= size_threshold;}
template <typename T>using Small = typename std::enable_if<is_small<T>(), shape>::type;
template <typename T>using Large = typename std::enable_if<(!is_small<T>()), shape>::type;
is_small<T>() is a predicate on type T to verify if it is small.Small<T> is type shape only if T is small.Large<T> is type shape only if T is not small.
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 82/97
Static versus dynamic polymorphism
Optimizing small objects
Selecting shapes move
shape.h
template <typename S,Small<S> ∗ = nullptr>
shape(S && s) noexcept {new (&buffer_) local_shape<S>{std::forward<S>(s)};
}
template <typename S,Large<S> ∗ = nullptr>
shape(S && s) noexcept {new (&buffer_) dynamic_shape<S>{std::forward<S>(s)};
}
Depending on size of T only one of them really exists.
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 83/97
Static versus dynamic polymorphism
Optimizing small objects
Simulating an empty selective constructor
shape.h
template <typename S>friend Small<S> make_shape() noexcept;
template <typename S>friend Large<S> make_shape() noexcept;
Allows to simulate an empty constructor with templateargument.make_shape() is a friend factory function.
Needs access to private empty constructor.
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 84/97
Static versus dynamic polymorphism
Optimizing small objects
Implementing factory functions
shape.h
template <typename S>shape::Small<S> make_shape() noexcept {
shape s;new (&s.buffer_) shape::local_shape<S>{};return s;
}
template <typename S>shape::Large<S> make_shape() noexcept {
shape s;new (&s.buffer_) shape::dynamic_shape<S>{};return s;
}
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 85/97
Static versus dynamic polymorphism
Optimizing small objects
Copy, move and destruction
shape.h
shape(const shape &) noexcept = delete;shape & operator=(const shape &) noexcept = delete;
shape(shape && s) noexcept {s. self ()−>placement_move(buffer_);
}
shape & operator=(shape &&) noexcept = delete;
~shape() noexcept {self ()−>~shape_base();
}
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 86/97
Static versus dynamic polymorphism
Optimizing small objects
Delegated functionality
shape.h
std :: string tagname() const { return self()−>tagname(); }int area() const noexcept { return self()−>area(); }void translate ( int dx, int dy) noexcept { self()−>translate(dx,dy); }void enlarge(int k) noexcept {self()−>enlarge(k); }
friend std :: ostream & operator<<(std::ostream & os, const shape & s){ return s. self ()−>insert(os); }
friend std :: istream & operator>>(std::istream & is, shape & s){ return s. self ()−>extract(is) ; }
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 87/97
Static versus dynamic polymorphism
Optimizing small objects
A simplified scene (again)
scene.h
class scene {public:
void add_shape(shape && s) { shapes_.push_back(std::forward<shape>(s)); }int size () const noexcept { return shapes_.size(); }
long long area() const noexcept ;void translate ( int dx, int dy) noexcept ;void enlarge(int k) noexcept;
friend std :: ostream & operator<<(std::ostream & os, const scene & s);friend std :: istream & operator>>(std::istream & is, scene & s);
private:std :: vector<shape> shapes_;
};
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 88/97
Static versus dynamic polymorphism
Optimizing small objects
Memory allocations
Classic: 25 memory allocations.
Object Oriented: 1,000,025 memory allocations.Type erased: 1,000,028 memory allocations.Type erased small object (size=16): 1,000,028 memoryallocations.Type erased small object (size=32): 28 memoryallocations.
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 89/97
Static versus dynamic polymorphism
Optimizing small objects
Memory allocations
Classic: 25 memory allocations.Object Oriented: 1,000,025 memory allocations.
Type erased: 1,000,028 memory allocations.Type erased small object (size=16): 1,000,028 memoryallocations.Type erased small object (size=32): 28 memoryallocations.
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 89/97
Static versus dynamic polymorphism
Optimizing small objects
Memory allocations
Classic: 25 memory allocations.Object Oriented: 1,000,025 memory allocations.Type erased: 1,000,028 memory allocations.
Type erased small object (size=16): 1,000,028 memoryallocations.Type erased small object (size=32): 28 memoryallocations.
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 89/97
Static versus dynamic polymorphism
Optimizing small objects
Memory allocations
Classic: 25 memory allocations.Object Oriented: 1,000,025 memory allocations.Type erased: 1,000,028 memory allocations.Type erased small object (size=16): 1,000,028 memoryallocations.
Type erased small object (size=32): 28 memoryallocations.
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 89/97
Static versus dynamic polymorphism
Optimizing small objects
Memory allocations
Classic: 25 memory allocations.Object Oriented: 1,000,025 memory allocations.Type erased: 1,000,028 memory allocations.Type erased small object (size=16): 1,000,028 memoryallocations.Type erased small object (size=32): 28 memoryallocations.
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 89/97
Static versus dynamic polymorphism
Optimizing small objects
Global execution time (area computation)
1k 10k 100k 1m 10m
100
101
102
103
Size
Exe
cutio
ntim
e(s
)
simpleobject-oriented
type erasedsmall size=16small size=32
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 90/97
Static versus dynamic polymorphism
Optimizing small objects
Global execution time (area computation)
10m0
1,000
2,000
3,000
Size
Exe
cutio
ntim
e(s
)
simpleobject-oriented
type erasedsmall size=16small size=32
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 91/97
Static versus dynamic polymorphism
Optimizing small objects
Normalized execution time (10 million elements)
Classic: 1.0Object Oriented: 1.20Type erased: 1.13Type erased small object (size=16): 1.22Type erased small object (size=32): 1.04
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 92/97
Static versus dynamic polymorphism
Optimizing small objects
Summary
Performance more critical now than object orientationbecame popular.
Forget dogmatism! Go back to principles!
Polymorphism is not necessarily dynamic polymorphism.
We also have static polymorphism.
Dynamic polymorphism implies in practice many smallmemory allocations.
Type erasure simplifies interfaces.
Small object optimization increases performance.
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 93/97
Static versus dynamic polymorphism
Optimizing small objects
Summary
Performance more critical now than object orientationbecame popular.
Forget dogmatism! Go back to principles!
Polymorphism is not necessarily dynamic polymorphism.
We also have static polymorphism.
Dynamic polymorphism implies in practice many smallmemory allocations.
Type erasure simplifies interfaces.
Small object optimization increases performance.
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 93/97
Static versus dynamic polymorphism
Optimizing small objects
Summary
Performance more critical now than object orientationbecame popular.
Forget dogmatism! Go back to principles!
Polymorphism is not necessarily dynamic polymorphism.
We also have static polymorphism.
Dynamic polymorphism implies in practice many smallmemory allocations.
Type erasure simplifies interfaces.
Small object optimization increases performance.
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 93/97
Static versus dynamic polymorphism
Optimizing small objects
Summary
Performance more critical now than object orientationbecame popular.
Forget dogmatism! Go back to principles!
Polymorphism is not necessarily dynamic polymorphism.We also have static polymorphism.
Dynamic polymorphism implies in practice many smallmemory allocations.
Type erasure simplifies interfaces.
Small object optimization increases performance.
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 93/97
Static versus dynamic polymorphism
Optimizing small objects
Summary
Performance more critical now than object orientationbecame popular.
Forget dogmatism! Go back to principles!
Polymorphism is not necessarily dynamic polymorphism.We also have static polymorphism.
Dynamic polymorphism implies in practice many smallmemory allocations.
Type erasure simplifies interfaces.
Small object optimization increases performance.
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 93/97
Static versus dynamic polymorphism
Optimizing small objects
Summary
Performance more critical now than object orientationbecame popular.
Forget dogmatism! Go back to principles!
Polymorphism is not necessarily dynamic polymorphism.We also have static polymorphism.
Dynamic polymorphism implies in practice many smallmemory allocations.
Type erasure simplifies interfaces.
Small object optimization increases performance.
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 93/97
Static versus dynamic polymorphism
Optimizing small objects
Summary
Performance more critical now than object orientationbecame popular.
Forget dogmatism! Go back to principles!
Polymorphism is not necessarily dynamic polymorphism.We also have static polymorphism.
Dynamic polymorphism implies in practice many smallmemory allocations.
Type erasure simplifies interfaces.
Small object optimization increases performance.
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 93/97
Static versus dynamic polymorphism
Optimizing small objects
A word on concepts
Concepts TS simplifies generic programming.
Concepts based programming
template <typename T>concept bool Small = sizeof(local_shape<T>) <= size_threshold;
template <Small S>shape make_shape() noexcept {
shape s;new (&s.buffer_) shape::local_shape<S>{};return s;
}
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 94/97
Static versus dynamic polymorphism
Optimizing small objects
A word about alignment
We can make sure that the buffer in shape is aligned.
Aligned buffer
using internal_buffer = typename std::aligned_buffer<size_threshold,size_threshold>::type;
However:C++14 does not guarantee allocation of over-aligned data.We cannot guarantee that a std::vector<shape> will be aligned.Unless we use a platform specific allocator(tbb::cache_aligned_allocator).C++17 solves this issue.
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 95/97
Static versus dynamic polymorphism
Optimizing small objects
Source code available
github.com/jdgarciauc3m/polyexamples
How to find me:
Twitter: @jdgarciauc3m
Web: www.arcos.inf.uc3m.es/wp/jdgarcia
E-mail: [email protected]
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 96/97
Static versus dynamic polymorphism
Optimizing small objects
Static versus dynamic polymorphismFlexibility versus performance
J. Daniel Garcia
ARCOS GroupUniversity Carlos III of Madrid
Spain
December 2, 2016
cbed – J. Daniel Garcia – ARCOS@UC3M ([email protected]) – Twitter: @jdgarciauc3m 97/97