Generic Programming Must Go - DConfdconf.org/2015/talks/alexandrescu.pdf · 2020-01-27 · Generic...

50
1 / 32 Generic Programming Must Go Andrei Alexandrescu

Transcript of Generic Programming Must Go - DConfdconf.org/2015/talks/alexandrescu.pdf · 2020-01-27 · Generic...

Page 1: Generic Programming Must Go - DConfdconf.org/2015/talks/alexandrescu.pdf · 2020-01-27 · Generic Programming 4 / 32 “...programming paradigm whereby fundamental requirements on

1 / 32

Generic Programming Must Go

Andrei Alexandrescu

Page 2: Generic Programming Must Go - DConfdconf.org/2015/talks/alexandrescu.pdf · 2020-01-27 · Generic Programming 4 / 32 “...programming paradigm whereby fundamental requirements on

Heap Building Blocks

2 / 32

Page 3: Generic Programming Must Go - DConfdconf.org/2015/talks/alexandrescu.pdf · 2020-01-27 · Generic Programming 4 / 32 “...programming paradigm whereby fundamental requirements on

Musings on Design

3 / 32

• Procedural: Work with unseen data

• OO, Functional: Work with unseen code and data

• Generic: Work with unseen code types and data layout

Page 4: Generic Programming Must Go - DConfdconf.org/2015/talks/alexandrescu.pdf · 2020-01-27 · Generic Programming 4 / 32 “...programming paradigm whereby fundamental requirements on

Generic Programming

4 / 32

“. . . programming paradigm whereby fundamental

requirements on types are abstracted from across concrete

examples of algorithms and data structures and formalised

as concepts, with generic functions implemented in terms of

these concepts. . . ” — Wikipedia

Page 5: Generic Programming Must Go - DConfdconf.org/2015/talks/alexandrescu.pdf · 2020-01-27 · Generic Programming 4 / 32 “...programming paradigm whereby fundamental requirements on

Generic Programming

5 / 32

+ Focus on algorithms

Page 6: Generic Programming Must Go - DConfdconf.org/2015/talks/alexandrescu.pdf · 2020-01-27 · Generic Programming 4 / 32 “...programming paradigm whereby fundamental requirements on

Generic Programming

5 / 32

+ Focus on algorithms

+ Good abstraction power

Page 7: Generic Programming Must Go - DConfdconf.org/2015/talks/alexandrescu.pdf · 2020-01-27 · Generic Programming 4 / 32 “...programming paradigm whereby fundamental requirements on

Generic Programming

5 / 32

+ Focus on algorithms

+ Good abstraction power

+ No indirection, so good speed

Page 8: Generic Programming Must Go - DConfdconf.org/2015/talks/alexandrescu.pdf · 2020-01-27 · Generic Programming 4 / 32 “...programming paradigm whereby fundamental requirements on

Generic Programming

5 / 32

+ Focus on algorithms

+ Good abstraction power

+ No indirection, so good speed

− Rigid; very limited adaptability

Page 9: Generic Programming Must Go - DConfdconf.org/2015/talks/alexandrescu.pdf · 2020-01-27 · Generic Programming 4 / 32 “...programming paradigm whereby fundamental requirements on

Generic Programming

5 / 32

+ Focus on algorithms

+ Good abstraction power

+ No indirection, so good speed

− Rigid; very limited adaptability

− Only works for small, scarce-vocabulary domains

Page 10: Generic Programming Must Go - DConfdconf.org/2015/talks/alexandrescu.pdf · 2020-01-27 · Generic Programming 4 / 32 “...programming paradigm whereby fundamental requirements on

Generic Programming

5 / 32

+ Focus on algorithms

+ Good abstraction power

+ No indirection, so good speed

− Rigid; very limited adaptability

− Only works for small, scarce-vocabulary domains

− Obsessed with naming everything

Page 11: Generic Programming Must Go - DConfdconf.org/2015/talks/alexandrescu.pdf · 2020-01-27 · Generic Programming 4 / 32 “...programming paradigm whereby fundamental requirements on

We’ve already “betrayed” GP

6 / 32

• InputRange, ForwardRange,

BidirectionalRange, RandomAccessRange

Page 12: Generic Programming Must Go - DConfdconf.org/2015/talks/alexandrescu.pdf · 2020-01-27 · Generic Programming 4 / 32 “...programming paradigm whereby fundamental requirements on

We’ve already “betrayed” GP

6 / 32

• InputRange, ForwardRange,

BidirectionalRange, RandomAccessRange

• hasLength, isInfinite, hasSlicing,

hasMobileElements

Page 13: Generic Programming Must Go - DConfdconf.org/2015/talks/alexandrescu.pdf · 2020-01-27 · Generic Programming 4 / 32 “...programming paradigm whereby fundamental requirements on

We’ve already “betrayed” GP

6 / 32

• InputRange, ForwardRange,

BidirectionalRange, RandomAccessRange

• hasLength, isInfinite, hasSlicing,

hasMobileElements

• By the canon: InputRangeWLength, ForwardRangeWLength,

BidirectionalRangeWLength, RandomAccessRangeWLength,

InputRangeInfinite, ForwardRangeInfinite,

BidirectionalRangeInfinite, RandomAccessRangeInfinite,

RandomAccessRangeWSlicing,

RandomAccessRangeWLengthWSlicing,

RandomAccessRangeInfiniteWSlicing, ...

Page 14: Generic Programming Must Go - DConfdconf.org/2015/talks/alexandrescu.pdf · 2020-01-27 · Generic Programming 4 / 32 “...programming paradigm whereby fundamental requirements on

7 / 32

And It Was Very Good

Page 15: Generic Programming Must Go - DConfdconf.org/2015/talks/alexandrescu.pdf · 2020-01-27 · Generic Programming 4 / 32 “...programming paradigm whereby fundamental requirements on

Uhm, Allocator Connection?

8 / 32

• Memory allocation is high-vocabulary

Page 16: Generic Programming Must Go - DConfdconf.org/2015/talks/alexandrescu.pdf · 2020-01-27 · Generic Programming 4 / 32 “...programming paradigm whereby fundamental requirements on

Uhm, Allocator Connection?

8 / 32

• Memory allocation is high-vocabulary

◦ alignment

Page 17: Generic Programming Must Go - DConfdconf.org/2015/talks/alexandrescu.pdf · 2020-01-27 · Generic Programming 4 / 32 “...programming paradigm whereby fundamental requirements on

Uhm, Allocator Connection?

8 / 32

• Memory allocation is high-vocabulary

◦ alignment

◦ (dynamically) aligned allocation

Page 18: Generic Programming Must Go - DConfdconf.org/2015/talks/alexandrescu.pdf · 2020-01-27 · Generic Programming 4 / 32 “...programming paradigm whereby fundamental requirements on

Uhm, Allocator Connection?

8 / 32

• Memory allocation is high-vocabulary

◦ alignment

◦ (dynamically) aligned allocation

◦ rounding up/quantization

Page 19: Generic Programming Must Go - DConfdconf.org/2015/talks/alexandrescu.pdf · 2020-01-27 · Generic Programming 4 / 32 “...programming paradigm whereby fundamental requirements on

Uhm, Allocator Connection?

8 / 32

• Memory allocation is high-vocabulary

◦ alignment

◦ (dynamically) aligned allocation

◦ rounding up/quantization

◦ in-place expansion

Page 20: Generic Programming Must Go - DConfdconf.org/2015/talks/alexandrescu.pdf · 2020-01-27 · Generic Programming 4 / 32 “...programming paradigm whereby fundamental requirements on

Uhm, Allocator Connection?

8 / 32

• Memory allocation is high-vocabulary

◦ alignment

◦ (dynamically) aligned allocation

◦ rounding up/quantization

◦ in-place expansion

◦ reallocation

Page 21: Generic Programming Must Go - DConfdconf.org/2015/talks/alexandrescu.pdf · 2020-01-27 · Generic Programming 4 / 32 “...programming paradigm whereby fundamental requirements on

Uhm, Allocator Connection?

8 / 32

• Memory allocation is high-vocabulary

◦ alignment

◦ (dynamically) aligned allocation

◦ rounding up/quantization

◦ in-place expansion

◦ reallocation

◦ contiguous vs. non-contiguous

Page 22: Generic Programming Must Go - DConfdconf.org/2015/talks/alexandrescu.pdf · 2020-01-27 · Generic Programming 4 / 32 “...programming paradigm whereby fundamental requirements on

Uhm, Allocator Connection?

8 / 32

• Memory allocation is high-vocabulary

◦ alignment

◦ (dynamically) aligned allocation

◦ rounding up/quantization

◦ in-place expansion

◦ reallocation

◦ contiguous vs. non-contiguous

◦ ownership

Page 23: Generic Programming Must Go - DConfdconf.org/2015/talks/alexandrescu.pdf · 2020-01-27 · Generic Programming 4 / 32 “...programming paradigm whereby fundamental requirements on

Uhm, Allocator Connection?

8 / 32

• Memory allocation is high-vocabulary

◦ alignment

◦ (dynamically) aligned allocation

◦ rounding up/quantization

◦ in-place expansion

◦ reallocation

◦ contiguous vs. non-contiguous

◦ ownership

◦ resolving internal pointers

Page 24: Generic Programming Must Go - DConfdconf.org/2015/talks/alexandrescu.pdf · 2020-01-27 · Generic Programming 4 / 32 “...programming paradigm whereby fundamental requirements on

Uhm, Allocator Connection?

8 / 32

• Memory allocation is high-vocabulary

◦ alignment

◦ (dynamically) aligned allocation

◦ rounding up/quantization

◦ in-place expansion

◦ reallocation

◦ contiguous vs. non-contiguous

◦ ownership

◦ resolving internal pointers

◦ deallocation

Page 25: Generic Programming Must Go - DConfdconf.org/2015/talks/alexandrescu.pdf · 2020-01-27 · Generic Programming 4 / 32 “...programming paradigm whereby fundamental requirements on

Uhm, Allocator Connection?

8 / 32

• Memory allocation is high-vocabulary

◦ alignment

◦ (dynamically) aligned allocation

◦ rounding up/quantization

◦ in-place expansion

◦ reallocation

◦ contiguous vs. non-contiguous

◦ ownership

◦ resolving internal pointers

◦ deallocation

◦ per-instance state vs. monostate

Page 26: Generic Programming Must Go - DConfdconf.org/2015/talks/alexandrescu.pdf · 2020-01-27 · Generic Programming 4 / 32 “...programming paradigm whereby fundamental requirements on

Uhm, Allocator Connection?

8 / 32

• Memory allocation is high-vocabulary

◦ alignment

◦ (dynamically) aligned allocation

◦ rounding up/quantization

◦ in-place expansion

◦ reallocation

◦ contiguous vs. non-contiguous

◦ ownership

◦ resolving internal pointers

◦ deallocation

◦ per-instance state vs. monostate

◦ thread-local vs. shared

Page 27: Generic Programming Must Go - DConfdconf.org/2015/talks/alexandrescu.pdf · 2020-01-27 · Generic Programming 4 / 32 “...programming paradigm whereby fundamental requirements on
Page 28: Generic Programming Must Go - DConfdconf.org/2015/talks/alexandrescu.pdf · 2020-01-27 · Generic Programming 4 / 32 “...programming paradigm whereby fundamental requirements on

10 / 32

Let’s Go Descartes!

Page 29: Generic Programming Must Go - DConfdconf.org/2015/talks/alexandrescu.pdf · 2020-01-27 · Generic Programming 4 / 32 “...programming paradigm whereby fundamental requirements on

Design by Introspection

11 / 32

Page 30: Generic Programming Must Go - DConfdconf.org/2015/talks/alexandrescu.pdf · 2020-01-27 · Generic Programming 4 / 32 “...programming paradigm whereby fundamental requirements on

Simplest Design That Could Possibly Work

12 / 32

• Make all allocation primitives optional, except:

◦ void[] allocate(size_t);

◦ enum uint alignment;

• All others optional, probed introspectively

• e.g. hasMember!(A, "expand")

• Combination allocators that define and adapt

capabilities to their “hosts”, in very little code

Page 31: Generic Programming Must Go - DConfdconf.org/2015/talks/alexandrescu.pdf · 2020-01-27 · Generic Programming 4 / 32 “...programming paradigm whereby fundamental requirements on

Simplest Allocator

13 / 32

• “Push the pointer”

struct Region {

private void* b, e, p;

this(void[] buf) {

p = b = buf.ptr;

e = b + buf.length;

}

enum uint alignment = 1;

void[] allocate(size_t n) {

if (e - p < n) return null;

auto result = p[0 .. n];

p += n;

return result;

}

}

Page 32: Generic Programming Must Go - DConfdconf.org/2015/talks/alexandrescu.pdf · 2020-01-27 · Generic Programming 4 / 32 “...programming paradigm whereby fundamental requirements on

Immediate Improvements

14 / 32

• Support better alignments (1 is seldom useful)

• Embed buffer

• Or, release buffer in destructor?

• More primitives such as deallocateAll

Page 33: Generic Programming Must Go - DConfdconf.org/2015/talks/alexandrescu.pdf · 2020-01-27 · Generic Programming 4 / 32 “...programming paradigm whereby fundamental requirements on

Simplest Composite Allocator

15 / 32

Let’s define FallbackAllocator: try one, then another

struct FallbackAllocator(P, F) {

P primary;

F fallback;

enum alignment = min(P.alignment,

F.alignment);

void[] allocate(size_t n) {

auto r = p.allocate(n);

if (r.length != n) r = f.allocate(n);

return r;

}

}

Page 34: Generic Programming Must Go - DConfdconf.org/2015/talks/alexandrescu.pdf · 2020-01-27 · Generic Programming 4 / 32 “...programming paradigm whereby fundamental requirements on

And Suddenly!

16 / 32

alias Local = FallbackAllocator!(

Region,

Mallocator

);

Page 35: Generic Programming Must Go - DConfdconf.org/2015/talks/alexandrescu.pdf · 2020-01-27 · Generic Programming 4 / 32 “...programming paradigm whereby fundamental requirements on

We Want Deallocation!

17 / 32

• Optional method: void deallocate(void[]);

static if (hasMember!(P, "owns")

&& (hasMember!(P, "deallocate")

|| hasMember!(F, "deallocate")))

void deallocate(void[] b) {

if (p.owns(b)) {

static if (hasMember!(P, "deallocate"))

primary.deallocate(b);

} else {

static if (hasMember!(F, "deallocate"))

return f.deallocate(b);

}

}

• Need a new method

• Only P must define owns

Page 36: Generic Programming Must Go - DConfdconf.org/2015/talks/alexandrescu.pdf · 2020-01-27 · Generic Programming 4 / 32 “...programming paradigm whereby fundamental requirements on

18 / 32

Let’s take a look at all

optional methods

Page 37: Generic Programming Must Go - DConfdconf.org/2015/talks/alexandrescu.pdf · 2020-01-27 · Generic Programming 4 / 32 “...programming paradigm whereby fundamental requirements on

Propagating owns

19 / 32

static if (hasMember!(P, "owns")

&& hasMember!(F, "owns"))

bool owns(void[] b) {

return p.owns(b) || f.owns(b);

}

Page 38: Generic Programming Must Go - DConfdconf.org/2015/talks/alexandrescu.pdf · 2020-01-27 · Generic Programming 4 / 32 “...programming paradigm whereby fundamental requirements on

How about reallocation?

20 / 32

bool reallocate(ref void[] b, size_t newSize) {

if (newSize == 0) {

static if (hasMember!(typeof(this), "deallocate"))

deallocate(b);

return true;

}

if (b is null) {

b = allocate(newSize);

return b !is null;

}

...

• (Note on introspection: “Would I be able to do that?”)

Page 39: Generic Programming Must Go - DConfdconf.org/2015/talks/alexandrescu.pdf · 2020-01-27 · Generic Programming 4 / 32 “...programming paradigm whereby fundamental requirements on

reallocate (2 of 3)

21 / 32

...

bool crossAllocatorMove(F, T)(ref F from, ref T to) {

auto b1 = to.allocate(newSize);

if (!b1.ptr) return false;

if (b.length < newSize) b1[0 .. b.length] = b[];

else b1[] = b[0 .. newSize];

static if (hasMember!(From, "deallocate"))

from.deallocate(b);

b = b1;

return true;

}

...

Page 40: Generic Programming Must Go - DConfdconf.org/2015/talks/alexandrescu.pdf · 2020-01-27 · Generic Programming 4 / 32 “...programming paradigm whereby fundamental requirements on

reallocate (the pride)

22 / 32

...

if (b is null || p.owns(b)) {

if (p.reallocate(b, newSize)) return true;

// Move from p to f

return crossAllocatorMove(p, f);

}

if (f.reallocate(b, newSize)) return true;

// Interesting. Move from f to p.

return crossAllocatorMove(f, p);

}

Page 41: Generic Programming Must Go - DConfdconf.org/2015/talks/alexandrescu.pdf · 2020-01-27 · Generic Programming 4 / 32 “...programming paradigm whereby fundamental requirements on

Global reallocate

23 / 32

bool reallocate(A)(ref A a, ref void[] b, size_t s) {

if (b.length == s) return true;

static if (hasMember!(A, "expand")) {

if (b.length <= s && a.expand(b, s - b.length))

return true;

}

auto r = a.allocate(s);

if (r.length != s) return false;

if (r.length <= b.length) r[] = b[0 .. newB.length];

else r[0 .. b.length] = b[];

static if (hasMember!(A, "deallocate"))

a.deallocate(b);

b = r;

return true;

}

Page 42: Generic Programming Must Go - DConfdconf.org/2015/talks/alexandrescu.pdf · 2020-01-27 · Generic Programming 4 / 32 “...programming paradigm whereby fundamental requirements on

Segregating by Size

24 / 32

struct Segregator(size_t threshold,

Small, Large) {

Small small;

Large large;

enum alignment = min(Small.alignment,

Large.alignment);

void[] allocate(size_t n) {

return n <= threshold

? small.allocate(n)

: large.allocate(n);

}

}

Page 43: Generic Programming Must Go - DConfdconf.org/2015/talks/alexandrescu.pdf · 2020-01-27 · Generic Programming 4 / 32 “...programming paradigm whereby fundamental requirements on

static if (hasMember!(SmallAllocator, "expand")

|| hasMember!(LargeAllocator, "expand"))

bool expand(ref void[] b, size_t delta) {

if (b.length + delta <= threshold) {

// Old and new allocations handled by _small

static if (hasMember!(SmallAllocator, "expand"))

return _small.expand(b, delta);

else

return false;

}

if (b.length > threshold) {

// Old and new allocations handled by _large

static if (hasMember!(LargeAllocator, "expand"))

return _large.expand(b, delta);

else

return false;

}

// Oops, cross-allocator transgression

return false;

}

Page 44: Generic Programming Must Go - DConfdconf.org/2015/talks/alexandrescu.pdf · 2020-01-27 · Generic Programming 4 / 32 “...programming paradigm whereby fundamental requirements on

Design by Introspection Tenets

26 / 32

• Compose designs from small pieces

• Distinguish required from optional methods

• No need to name all combinations

◦ Generic Programming is fail

◦ Concepts are fail

• Assemble using introspection

• Use Boolean logic and static if

◦ Constrain types and signatures

• Yay

Page 45: Generic Programming Must Go - DConfdconf.org/2015/talks/alexandrescu.pdf · 2020-01-27 · Generic Programming 4 / 32 “...programming paradigm whereby fundamental requirements on

Take a look

27 / 32

• https://github.com/andralex/phobos/tree/

allocator/std/experimental/allocator

• http://erdani.com/d/phobos-prerelease/

std experimental allocator.html

Page 46: Generic Programming Must Go - DConfdconf.org/2015/talks/alexandrescu.pdf · 2020-01-27 · Generic Programming 4 / 32 “...programming paradigm whereby fundamental requirements on

Perk: Ouroboros Style

28 / 32

Page 47: Generic Programming Must Go - DConfdconf.org/2015/talks/alexandrescu.pdf · 2020-01-27 · Generic Programming 4 / 32 “...programming paradigm whereby fundamental requirements on

Array of Allocators: Going Too Meta?

29 / 32

• Goal:

◦ Define an array of generic allocators

• e.g. Regions, HeapBlocks. . .

◦ Grow and shrink the array per application needs

◦ Keep some per-allocator metadata

• Question:

◦ Where do you store the array?

Page 48: Generic Programming Must Go - DConfdconf.org/2015/talks/alexandrescu.pdf · 2020-01-27 · Generic Programming 4 / 32 “...programming paradigm whereby fundamental requirements on

Solution: Going Ouroboros!

30 / 32

• Create an allocator on the stack

• Use it to allocate the needed metadata memory

• Move it to that memory

• Keep a pointer to the metadata in the meta-allocator

• Problem solved

Page 49: Generic Programming Must Go - DConfdconf.org/2015/talks/alexandrescu.pdf · 2020-01-27 · Generic Programming 4 / 32 “...programming paradigm whereby fundamental requirements on

Summary

31 / 32

• Generic Programming insufficient for flexible designs

• Design by Introspection being proposed

• Give components required and optional APIs

• Use introspection to assemble larger designs from

small components

Page 50: Generic Programming Must Go - DConfdconf.org/2015/talks/alexandrescu.pdf · 2020-01-27 · Generic Programming 4 / 32 “...programming paradigm whereby fundamental requirements on

For My Money

32 / 32

Static introspection + CTFE + Boolean constraints

+ static if = WIN