the power of none andrei alexandrescu petru marginean

24
1 The Power of None Andrei Alexandrescu Petru Marginean

Upload: arav

Post on 20-Jan-2016

37 views

Category:

Documents


0 download

DESCRIPTION

The Power of None Andrei Alexandrescu Petru Marginean. Agenda. Exceptions: WTF? Why The Frenzy? Top 3 problems with exceptions Help from the type system The None type The Likely type Conclusions. Exceptions: teleology. Most of us took them non-critically - PowerPoint PPT Presentation

TRANSCRIPT

Page 1: The Power of  None Andrei Alexandrescu Petru Marginean

1

The Power of None

Andrei AlexandrescuPetru Marginean

Page 2: The Power of  None Andrei Alexandrescu Petru Marginean

2

Agenda

Exceptions: WTF? Why The Frenzy?

Top 3 problems with exceptions Help from the type system

The None type The Likely<T> type

Conclusions

Page 3: The Power of  None Andrei Alexandrescu Petru Marginean

3

Exceptions: teleology

Most of us took them non-critically “Here’s the construct… use it”

What’s a proper baseline? What were their design goals? What were their intended use cases? How do their semantics support the use cases? What were the consequences of their design? How to write code playing on their strengths?

Page 4: The Power of  None Andrei Alexandrescu Petru Marginean

4

Desiderata

General: learn once use many Minimize soft errors; maximize hard errors

Avoid metastable states Allow centralized handling

Keep error handling out of most code Allow local handling

Not all error handling can/should be centralized

Transport an arbitrary amount of error info Exact little cost on the normal path Make correct code easy to write

Page 5: The Power of  None Andrei Alexandrescu Petru Marginean

5

Inventing Exceptions

int atoi(const char * s); What’s wrong with it?

Returns zero on error “0”, “ 0”, “ +000 ” are all valid inputs Zero is a commonly-encountered value atoi is a surjection

Distinguish valid from invalid input a posteriori is almost as hard as a priori!

Page 6: The Power of  None Andrei Alexandrescu Petru Marginean

6

Inventing Exceptions

Four solutions for returning error information: Set global state

The errno approach Encode error information as a special

returned valuethe out-of-band value approach

Encode error information as a value of a distinct typethe “error code return” approach

Exceptions

Page 7: The Power of  None Andrei Alexandrescu Petru Marginean

7

errno

+ General - Minimize soft errors + Centralized handling + Local handling + Arbitrary amount of error info + Little cost on the normal path - Make correct code easy to write

Error handling entirely optional Threading issues

Page 8: The Power of  None Andrei Alexandrescu Petru Marginean

8

Special value

- General (won’t work with surjective functions) - Minimize soft errors - Centralized handling + Local handling - Arbitrary amount of error info ? Little cost on the normal path - Make correct code easy to write

Error handling often optional Error handling code intertwined with normal

code

Page 9: The Power of  None Andrei Alexandrescu Petru Marginean

9

Value of separate type

+ General ? Minimize soft errors - Centralized handling + Local handling + Arbitrary amount of error info + Little cost on the normal path - Make correct code easy to write

Error handling requires much extra code & data E.g. strtol(const char* s, const char ** e, int r);

Page 10: The Power of  None Andrei Alexandrescu Petru Marginean

10

Exceptions?

1. We want to pass arbitrary error info around:

class invalid_input { … };int|invalid_input atoi(const char * str);int|invalid_input r = atoi(some_string);typeswitch (result) {case int x { … }case invalid_input err { … }};

Page 11: The Power of  None Andrei Alexandrescu Petru Marginean

11

Exceptions? (cont’d)

2. We want to allow centralized error handling Break the typeswitch => covert return types!

overt<int>|convert<invalid_input> atoi(const char*);

Local code should afford to ignore invalid_input

=> A function has an overt return type plus one or more covert return types

Q: Where do the covert return values go?

Page 12: The Power of  None Andrei Alexandrescu Petru Marginean

12

Exceptions (cont’d)

We also want centralized error handling Covert values must “return” to a caller upper

in the dynamic invocation chain Only certain callers understand certain errors => Covert returned types come together with

covert execution paths! => Callers plant return points collecting such

types => Type-based, first-match exception

handling

Page 13: The Power of  None Andrei Alexandrescu Petru Marginean

13

Exceptions: Aftermath

+ General ? Minimize soft errors + Centralized handling - Local handling + Arbitrary amount of error info + Little cost on the normal path ? Make correct code easy to write

1986: yes 1996: no 2006: maybe

Page 14: The Power of  None Andrei Alexandrescu Petru Marginean

14

Top 3 Issues with Exceptions

Metastable states User must ensure transactional semantics

DestructorsScopeGuard

Make local error handling unduly hard/asymmetric By-value semantics prevent library

approaches Hard to analyze

By human and by machine

Page 15: The Power of  None Andrei Alexandrescu Petru Marginean

15

Today

+ Local handling + Minimize soft errors + Make correct code easier to write

Page 16: The Power of  None Andrei Alexandrescu Petru Marginean

16

The None type

Returned by a function with no overt returns:None Abort();None Exit(int code);None LoopForever(); Properties:

Can be substituted for any typeThe bottom of the type hierarchy

Destructor throws Noncopyable

Page 17: The Power of  None Andrei Alexandrescu Petru Marginean

17

Creating None

class None { None(const char * info = “”) info_(info) {} template <class T> operator T&() const { throw runtime_error(info_); }}; Conversion to reference allows lvalues and

rvalues

Page 18: The Power of  None Andrei Alexandrescu Petru Marginean

18

Using None

int FindSomethingIKnowIsThere(const T& obj) {

for (int i = 0; i != size; ++i) { if (obj == collection[i]) return i; } return None();} Returning None is like throw, but more type-

versatile Not very exciting so far

Page 19: The Power of  None Andrei Alexandrescu Petru Marginean

19

Likely<T>

Idea: We want to express an overt type plus a covert type Normal case: value of overt type is there Erroneous case: a value of type None is there

Unify local and central error handlingLikely<int> atoi(const char *); Wanna local? Check against None() Wanna centralized? Use Likely<T> as you’d

use a T

Page 20: The Power of  None Andrei Alexandrescu Petru Marginean

20

Creating Likely<T>

template <class T> struct Likely { Likely(const None& none); Likely(const T& v); ~Likely(); // throws if not compared against None operator T&() const; template <class U> friend bool operator==(const Likely<U>& lhs, const

None&);private: T value_; None nonValue_;};

Page 21: The Power of  None Andrei Alexandrescu Petru Marginean

21

Using Likely<T>: Centralized

Centralized error handling: convert Likely<T> to T& liberally

Exception is thrown if the object is a dud Code is similar to that with entirely covert

returnsint x = atoi(some_string); Separate normal path from error path Just like with exceptions

Page 22: The Power of  None Andrei Alexandrescu Petru Marginean

22

Using Likely<T>: Local

Localized error handling:Likely<int> r = atoi(some_string);if (r == None()) { … local error handling} Just like good ol’ error handling with special

values Exacts a tad more cost Can specialize to alleviate cost

No more issues with surjections => general!

Page 23: The Power of  None Andrei Alexandrescu Petru Marginean

23

Using Likely<T>: Ignoramus

If: A Likely<T> object is a dud && Nobody attempts to dereference it && Nobody checks it against None

Then: Likely<T>’s destructor throws an exception

Keeps error handling required Avoids metastable states Easy to supress: IGNORE_ERROR(atoi(str));

Page 24: The Power of  None Andrei Alexandrescu Petru Marginean

24

Conclusions

Exceptions’ design address a complicated web of desiderata Fails to provide complete solution Better than others Requires a shift in code writing style

Possible to make local and central error handling interchangeable Type system can help Keeps error handling required Avoid asymmetry