Upgrade to Pro — share decks privately, control downloads, hide ads and more …

The Curiously Recurring Pattern of Coupled Types

The Curiously Recurring Pattern of Coupled Types

Why can pointers be subtracted but not added?
What do raw C pointers, STL iterators, std::chrono types, and 2D/3D geometric primitives have in common?
In this talk we will present some curiously coupled data types that frequently occur in your programs, together forming notions that you are already intuitively familiar with. We will shine a light on the mathematical notion of Affine Spaces, and how they guide stronger design. We will review the properties of affine spaces and show how they improve program semantics, stronger type safety and compile time enforcement of these semantics.
By showing motivational examples, we will introduce you to the mathematical notion of affine spaces. The main focus will then be on how affine space types and their well defined semantics shape expressive APIs.
We will give examples and guidelines for creating your own affine types.

This talk was given together with Adi Shavit from CoreC++, Israel.

Björn Fahller

October 25, 2018
Tweet

More Decks by Björn Fahller

Other Decks in Programming

Transcript

  1. @bjorn_fahller :: @adishavit The Curiously Recurring Coupled Types Pattern Adi

    Shavit and Björn Fahller @adishavit :: @bjorn_fahller
  2. @bjorn_fahller :: @adishavit Curious API Pattern Examples

  3. @bjorn_fahller :: @adishavit v1 Vec2D v1{...}; 2D Space

  4. @bjorn_fahller :: @adishavit v1 v2 Vec2D v1{...}; Vec2D v2{...}; 2D

    Space
  5. @bjorn_fahller :: @adishavit v1 v2 Vec2D v1{...}; Vec2D v2{...}; 2D

    Space
  6. @bjorn_fahller :: @adishavit v1 v2 v3 Vec2D v1{...}; Vec2D v2{...};

    auto v3 = v1+v2; 2D Space
  7. @bjorn_fahller :: @adishavit v1 v2 v1 + v2 -v2 Vec2D

    v1{...}; Vec2D v2{...}; auto v3 = v1+v2; -v2; 2D Space
  8. @bjorn_fahller :: @adishavit v1 v2 v1 + v2 -v2 Vec2D

    v1{...}; Vec2D v2{...}; auto v3 = v1+v2; -v2; 2D Space
  9. @bjorn_fahller :: @adishavit v1 v2 v1 + v2 -v2 v1

    - v2 Vec2D v1{...}; Vec2D v2{...}; auto v3 = v1+v2; auto v4 = v1-v2; 2D Space
  10. @bjorn_fahller :: @adishavit v1 v2 v1 + v2 -v2 v1

    - v2 2 * v2 Vec2D v1{...}; Vec2D v2{...}; auto v3 = v1+v2; auto v4 = v1-v2; auto v5 = 2*v2; 2D Space
  11. @bjorn_fahller :: @adishavit v1 v2 v1 + v2 -v2 v1

    - v2 2 * v2 Vec2D v1{...}; Vec2D v2{...}; auto v3 = v1+v2; auto v4 = v1-v2; auto v5 = 2*v2; v1 * v2 2D Space
  12. @bjorn_fahller :: @adishavit v1 v2 v1 + v2 -v2 v1

    - v2 2 * v2 Vec2D v1{...}; Vec2D v2{...}; auto v3 = v1+v2; auto v4 = v1-v2; auto v5 = 2*v2; v1 * v2 2D Space
  13. @bjorn_fahller :: @adishavit p1 Position p1{...}; 2D Space

  14. @bjorn_fahller :: @adishavit Position p1{...}; Position p2{...}; p1 p2 2D

    Space
  15. @bjorn_fahller :: @adishavit Position p1{...}; Position p2{...}; p2 - p1;

    p1 p2 p2 - p1 2D Space
  16. @bjorn_fahller :: @adishavit Position p1{...}; Position p2{...}; Vec2D v =

    p2 - p1; p1 p2 p2 - p1 2D Space
  17. @bjorn_fahller :: @adishavit Position p1{...}; Position p2{...}; Vec2D v =

    p2 - p1; Vec2D v2{...}; v2 p1 p2 p2 - p1 2D Space
  18. @bjorn_fahller :: @adishavit Position p1{...}; Position p2{...}; Vec2D v =

    p2 - p1; Vec2D v2{...}; auto p3 = p1 + v2; p3 v2 p1 p2 p2 - p1 2D Space
  19. @bjorn_fahller :: @adishavit Position p1{...}; Position p2{...}; Vec2D v =

    p2 - p1; Vec2D v2{...}; auto p3 = p1 + v2; p3 + p2 p3 v2 p1 p2 p2 - p1 2D Space
  20. @bjorn_fahller :: @adishavit Position p1{...}; Position p2{...}; Vec2D v =

    p2 - p1; Vec2D v2{...}; auto p3 = p1 + v2; p3 + p2 p3 v2 p1 p2 p2 - p1 2D Space
  21. @bjorn_fahller :: @adishavit Do we have time?

  22. @bjorn_fahller :: @adishavit <chrono>

  23. @bjorn_fahller :: @adishavit <chrono>

  24. @bjorn_fahller :: @adishavit <chrono> ?

  25. @bjorn_fahller :: @adishavit <chrono>

  26. @bjorn_fahller :: @adishavit <chrono> timepoint timepoint duration

  27. @bjorn_fahller :: @adishavit <chrono> timepoint timepoint ?

  28. @bjorn_fahller :: @adishavit <chrono> timepoint timepoint duration

  29. @bjorn_fahller :: @adishavit Pointer Arithmetic

  30. @bjorn_fahller :: @adishavit Let’s dive into pointer arithmetics! A array[]

    =
  31. @bjorn_fahller :: @adishavit Pointer arithmetics! A array[] = A* p1

    =
  32. @bjorn_fahller :: @adishavit Pointer arithmetics! A array[] = A* p1

    = A* p2 =
  33. @bjorn_fahller :: @adishavit Pointer arithmetics! A array[] = A* p1

    = A* p2 = auto d = p2 - p1
  34. @bjorn_fahller :: @adishavit Pointer arithmetics! A array[] = A* p1

    = A* p2 = auto d = p2 - p1
  35. @bjorn_fahller :: @adishavit Pointer arithmetics! A array[] = A* p1

    = A* p2 = auto d = p2 - p1 auto s = p2 + p1
  36. @bjorn_fahller :: @adishavit Pointer arithmetics! A array[] = A* p1

    = A* p2 = auto d = p2 - p1 auto s = p2 + p1
  37. @bjorn_fahller :: @adishavit Pointer arithmetics! A array[] = A* p1

    = A* p2 = auto d = p2 - p1 auto x = p2 - d
  38. @bjorn_fahller :: @adishavit Are we seeing it yet?

  39. @bjorn_fahller :: @adishavit Meanwhile on Twitter...

  40. @bjorn_fahller :: @adishavit The Affine Space Intuitively: 1. A point:

    a position specified with coordinate values ◦ a.k.a. location, address... 2. A vector: the difference between two points ◦ a.k.a. shift, offset, displacement, duration... If an origin is specified, then a point can be represented by a vector from the origin, however, a point is still not a vector in coordinate-free concepts.
  41. @bjorn_fahller :: @adishavit The Affine Space: Definitions affine space points

    vectors scalars vector space scalar affine space v p q ▪ p-q=v ▪ p+v=q
  42. @bjorn_fahller :: @adishavit The Affine Space Type API Point Vector

    Scalar Vector operations Vector + Vector -> Vector scalar * Vector -> Vector Vector * Scalar -> Vector Vector - Vector -> Vector -Vector -> Vector Affine operations Point - Point -> Vector Point + Vector -> Point Point - Vector -> Point
  43. @bjorn_fahller :: @adishavit <chrono>

  44. @bjorn_fahller :: @adishavit using namespace std::chrono; auto beg = system_clock::now();

    // start time // ... auto end = system_clock::now(); // end time auto dur = end - beg; // total duration auto almost = beg + dur - 1ms; // just before end auto next = beg + 2*dur; // twice as long auto ago = beg - end; // a negative time offset auto utcnow = utc_clock::now(); // UTC time (C++20) auto utcnxt = utcnow + 2*dur; // OK: when auto meh = utcnow - beg; // ??? <chrono>
  45. @bjorn_fahller :: @adishavit using namespace std::chrono; auto beg = system_clock::now();

    // start time // ... auto end = system_clock::now(); // end time auto dur = end - beg; // total duration auto almost = beg + dur - 1ms; // just before end auto next = beg + 2*dur; // twice as long auto ago = beg - end; // a negative time offset auto utcnow = utc_clock::now(); // UTC time (C++20) auto utcnxt = utcnow + 2*dur; // OK: when auto meh = utcnow - beg; // ERROR! <chrono>
  46. @bjorn_fahller :: @adishavit Iterators

  47. @bjorn_fahller :: @adishavit Iterators using T = float; std::vector<T> vec

    = {0,1,2,3}; auto beg = vec.begin(); auto end = vec.end(); int cnt = end - beg; auto last = beg + cnt - 1; int neg = beg - end; using T = float; std::set<T> set={0,1,2,3}; auto beg = set.begin(); auto end = set.end(); auto cnt = std::distance(beg, end); auto last = std::next(beg, cnt - 1); auto neg = std::distance(end, beg);
  48. @bjorn_fahller :: @adishavit Counter Examples using namespace cv; Point pos

    = { 0,0 }; Point next_pos = pos + Point{Vec2i{ 42,0 }}; // WAT? Point dir = next_pos - pos; // Umm.. Point huh = -pos; // Huh? Point hmm = pos * 2; // Hmmm...
  49. @bjorn_fahller :: @adishavit Remember the Mars Climate Orbiter pound-force seconds

    newton seconds,
  50. @bjorn_fahller :: @adishavit An Imaginary GUI library

  51. @bjorn_fahller :: @adishavit An Imaginary GUI library using Size =

    Vec2D; class Window { public: Window(Point bl, Size size); ... ... }; Point p1{...}; Point p2{...}; Window w{p1, p2-p1};
  52. @bjorn_fahller :: @adishavit An Imaginary GUI library using Size =

    Vec2D; class Window { public: Window(Point bl, Size size); void translate(Vec2D offset); ... }; Point p1{...}; Point p2{...}; Window w{p1, p2-p1}; w.translate(p2-p1);
  53. @bjorn_fahller :: @adishavit An Imaginary GUI library using Size =

    Vec2D; class Window { public: Window(Point bl, Size size); void translate(Vec2D offset); void move_to(Point dst); }; Point p1{...}; Point p2{...}; Window w{p1, p2-p1}; w.translate(p2-p1); w.move_to(p1);
  54. @bjorn_fahller :: @adishavit Demo github.com/rollbear/affine_types gcc.godbolt.org/z/IJLKFG

  55. @bjorn_fahller :: @adishavit Affine Space Concepts template <typename P, typename

    V, typename S> concept Affine_space = Regular<P> and Vector_space<V, S> and requires (P const& p, V const& v) { { p - p } -> V; { p + v } -> P; { p - v } -> P; } and requires (P& p, V const& v) { { p += v } -> P&; { p -= v } -> P&; }; } https://github.com/petter-holmberg/elements
  56. @bjorn_fahller :: @adishavit The Affine Combination affine combination 1 ⇒

    point 0 ⇒ vector undefined barycentric coordinates
  57. @bjorn_fahller :: @adishavit The Affine Combination m=(a+b)/2 // midpoint int

    a,b m=(a+b)/2 m int* a; int* b; m=(a+b)/2 m=a+(b-a)/2 ½*a+½*b ⇒ ← Affine Combination! p q r (p+q+r)/3 CoG = ⅓*p + ⅓*q + ⅓*r ⇒ ⅓ ⅓ ⅓
  58. @bjorn_fahller :: @adishavit Summary • about the semantics to help

    build the types • strong APIs: ⇔ ◦ ⇒ A semantically incorrect expression becomes a compilation error • Affine-space type-relations are very common • them and math delivers a powerful and consistent API • : Learn more about the math of types: Abstract Algebra, Category Theory When in doubt, do what <chrono> does!
  59. @bjorn_fahller :: @adishavit Resources • Affine Space Types: Adi Shavit,

    blog post (+many links) ◦ videocortex.io/2018/Affine-Space-Types/ • Type safe C++ – LOL! :-) Björn Fahller, ACCU 2018 ◦ youtu.be/SWHvNvY-PHw • Operator Overloading: History, Principles and Practice, Ben Deane, CppCon 2018 ◦ youtu.be/zh4EgO13Etg?t=831 (@13:53) • Compiler Explorer “GUI” code example ◦ gcc.godbolt.org/z/IJLKFG
  60. @bjorn_fahller :: @adishavit @adishavit @bjorn_fahller @rollbear @longbeard The Curiously Recurring

    Pattern of Coupled Types
  61. @bjorn_fahller :: @adishavit Why can pointers be subtracted but not

    added? What do raw C pointers, STL iterators, std::chrono types, and 2D/3D geometric primitives have in common? In this talk we will present some curiously coupled data types that frequently occur in your programs, together forming notions that you are already intuitively familiar with. We will shine a light on the mathematical notion of Affine Spaces, and how they guide stronger design. We will review the properties of affine spaces and show how they improve program semantics, stronger type safety and compile time enforcement of these semantics. By showing motivational examples, we will introduce you to the mathematical notion of affine spaces. The main focus will then be on how affine space types and their well defined semantics shape expressive APIs. We will give examples and guidelines for creating your own affine types. * Show familiar examples of situations of affine space semantics - pointer arithmetic - iterators - chrono - coordinate systems * Mathematical definitions/properties * Describe properties of affine space types - operators and relations - [show a Concept for affine space types, tbd] * Show how to write a simple affine space strong type template. * Parallels to unit systems