SlideShare a Scribd company logo
1 of 23
Download to read offline
© 2014- Andrei Alexandrescu. Do not redistribute. 1 / 46
Declarative Control Flow
Prepared for NDC Oslo 2014
Andrei Alexandrescu, Ph.D.
andrei@erdani.com
Agenda
© 2014- Andrei Alexandrescu. Do not redistribute. 2 / 46
• Motivation
• Implementation
• Use cases
© 2014- Andrei Alexandrescu. Do not redistribute. 3 / 46
action
cleanup
next
rollback
C
© 2014- Andrei Alexandrescu. Do not redistribute. 4 / 46
if ( action ) {
if (! next ) {
rollback
}
cleanup
}
C++
© 2014- Andrei Alexandrescu. Do not redistribute. 5 / 46
class RAII {
RAII() { action }
~RAII() { cleanup }
};
...
RAII raii;
try {
next
} catch (...) {
rollback
throw;
}
Java, C#
© 2014- Andrei Alexandrescu. Do not redistribute. 6 / 46
action
try {
next
} catch (Exception e) {
rollback
throw e;
} finally {
cleanup
}
Go
© 2014- Andrei Alexandrescu. Do not redistribute. 7 / 46
result, error := action
if error != nil {
defer cleanup
if ! next
rollback
}
Composition
C
© 2014- Andrei Alexandrescu. Do not redistribute. 9 / 46
if ( action1 ) {
if ( action2 ) {
if (! next2 ) {
rollback2
rollback1
}
cleanup2
} else {
rollback1
}
cleanup1
}
C (Pros Only)
© 2014- Andrei Alexandrescu. Do not redistribute. 10 / 46
if (! action1 ) {
goto done;
}
if (! action2 ) {
goto r1;
}
if (! next2 ) {
goto r2;
}
cleanup2
goto c1;
r2: rollback2
cleanup2
r1: rollback1
c1: cleanup1
done: ;
C++
© 2014- Andrei Alexandrescu. Do not redistribute. 11 / 46
class RAII1 {
RAII1() { action1 }
~RAII1() { cleanup1 }
};
class RAII2 {
RAII2() { action2 }
~RAII2() { cleanup2 }
};
...
C++
© 2014- Andrei Alexandrescu. Do not redistribute. 12 / 46
RAII1 raii1;
try {
RAII2 raii2;
try {
next2
} catch (...) {
rollback2
throw;
}
} catch (...) {
rollback1
throw;
}
Java, C#
© 2014- Andrei Alexandrescu. Do not redistribute. 13 / 46
action1
try {
action2
try {
next2
} catch (Exception e) {
rollback2
throw e;
} finally {
cleanup2
}
} catch (Exception e) {
rollback1
throw e;
} finally {
cleanup1
}
Go
© 2014- Andrei Alexandrescu. Do not redistribute. 14 / 46
result1, error := action1
if error != nil {
defer cleanup1
result2, error := action2
if error != nil {
defer cleanup2
if ! next2
rollback2
} else {
rollback2
}
}
© 2014- Andrei Alexandrescu. Do not redistribute. 15 / 46
Explicit Control Flow =
Fail
Declarative Programming
© 2014- Andrei Alexandrescu. Do not redistribute. 16 / 46
• Focus on stating needed accomplishments
• As opposed to describing steps
• Control flow typically minimal/absent
• Execution is implicit, not explicit
• Examples: SQL, regex, make, config,. . .
• Let’s take a page from their book!
According to Seinfeld
© 2014- Andrei Alexandrescu. Do not redistribute. 17 / 46
Declarative: airplane
ticket
Imperative: what the
pilot does
Surprising Insight
© 2014- Andrei Alexandrescu. Do not redistribute. 18 / 46
• Consider bona fide RAII with destructors:
States needed accomplishment?
Implicit execution?
Control flow minimal?
• RAII is declarative programming!
More RAII: ScopeGuard
© 2014- Andrei Alexandrescu. Do not redistribute. 19 / 46
• Also declarative
• Less syntactic baggage than cdtors
• Flow is “automated” through placement
• Macro SCOPE_EXIT raises it to
pseudo-statement status
Pseudo-Statement (NDC workshop re-
cap!)
© 2014- Andrei Alexandrescu. Do not redistribute. 20 / 46
namespace detail {
enum class ScopeGuardOnExit {};
template <typename Fun>
ScopeGuard<Fun>
operator+(ScopeGuardOnExit, Fun&& fn) {
return ScopeGuard<Fun>(std::forward<Fun>(fn));
}
}
#define SCOPE_EXIT 
auto ANONYMOUS_VARIABLE(SCOPE_EXIT_STATE) 
= ::detail::ScopeGuardOnExit() + [&]()
Preprocessor Trick (NDC workshop re-
cap!)
© 2014- Andrei Alexandrescu. Do not redistribute. 21 / 46
#define CONCATENATE_IMPL(s1, s2) s1##s2
#define CONCATENATE(s1, s2) CONCATENATE_IMPL(s1, s2)
#ifdef __COUNTER__
#define ANONYMOUS_VARIABLE(str) 
CONCATENATE(str, __COUNTER__)
#else
#define ANONYMOUS_VARIABLE(str) 
CONCATENATE(str, __LINE__)
#endif
Use (NDC workshop recap!)
© 2014- Andrei Alexandrescu. Do not redistribute. 22 / 46
void fun() {
char name[] = "/tmp/deleteme.XXXXXX";
auto fd = mkstemp(name);
SCOPE_EXIT { fclose(fd); unlink(name); };
auto buf = malloc(1024 * 1024);
SCOPE_EXIT { free(buf); };
... use fd and buf ...
}
(if no “;” after lambda, error message is meh)
Painfully Close to Ideal!
© 2014- Andrei Alexandrescu. Do not redistribute. 23 / 46
action1
SCOPE_EXIT { cleanup1 };
SCOPE_FAIL { rollback1 }; // nope
action2
SCOPE_EXIT { cleanup2 };
SCOPE_FAIL { rollback2 }; // nope
next2
• Note: slide plagiated from C&B 2012
One more for completeness
© 2014- Andrei Alexandrescu. Do not redistribute. 24 / 46
action
SCOPE_SUCCESS { celebrate };
next
• Powerful flow-declarative trifecta!
• Do not specify flow
• Instead declare circumstances and goals
© 2014- Andrei Alexandrescu. Do not redistribute. 25 / 46
Can be implemented
today on ALL major
compilers
© 2014- Andrei Alexandrescu. Do not redistribute. 26 / 46
May become 100%
portable:
http://isocpp.org/files/papers/N3614.pdf
Credits
© 2014- Andrei Alexandrescu. Do not redistribute. 27 / 46
• Evgeny Panasyuk: compiler-specific bits
github.com/panaseleus/stack_unwinding
• Daniel Marinescu: folly implementation
github.com/facebook/folly
Underpinnings
© 2014- Andrei Alexandrescu. Do not redistribute. 28 / 46
class UncaughtExceptionCounter {
int getUncaughtExceptionCount() noexcept;
int exceptionCount_;
public:
UncaughtExceptionCounter()
: exceptionCount_(getUncaughtExceptionCount()) {
}
bool isNewUncaughtException() noexcept {
return getUncaughtExceptionCount()
> exceptionCount_;
}
};
• Only detail left: getUncaughtExceptionCount()
gcc/clang
© 2014- Andrei Alexandrescu. Do not redistribute. 29 / 46
inline int UncaughtExceptionCounter::
getUncaughtExceptionCount() noexcept {
// __cxa_get_globals returns a __cxa_eh_globals*
// (defined in unwind-cxx.h).
// The offset below returns
// __cxa_eh_globals::uncaughtExceptions.
return *(reinterpret_cast<int*>(
static_cast<char*>(
static_cast<void*>(
__cxxabiv1::__cxa_get_globals()))
+ sizeof(void*)));
}
gcc/clang
© 2014- Andrei Alexandrescu. Do not redistribute. 30 / 46
namespace __cxxabiv1 {
// defined in unwind-cxx.h from from libstdc++
struct __cxa_eh_globals;
// declared in cxxabi.h from libstdc++-v3
extern "C"
__cxa_eh_globals* __cxa_get_globals() noexcept;
}
MSVC 8.0+
© 2014- Andrei Alexandrescu. Do not redistribute. 31 / 46
struct _tiddata;
extern "C" _tiddata* _getptd();
inline int UncaughtExceptionCounter::
getUncaughtExceptionCount() noexcept {
// _getptd() returns a _tiddata*
// (defined in mtdll.h).
// The offset below returns
// _tiddata::_ProcessingThrow.
return *(reinterpret_cast<int*>(static_cast<char*>(
static_cast<void*>(_getptd()))
+ sizeof(void*) * 28 + 0x4 * 8));
}
Layering
© 2014- Andrei Alexandrescu. Do not redistribute. 32 / 46
template <typename FunctionType, bool executeOnException>
class ScopeGuardForNewException {
FunctionType function_;
UncaughtExceptionCounter ec_;
public:
explicit ScopeGuardForNewException(const FunctionType& fn)
: function_(fn) {
}
explicit ScopeGuardForNewException(FunctionType&& fn)
: function_(std::move(fn)) {
}
~ScopeGuardForNewException() noexcept(executeOnException) {
if (executeOnException == ec_.isNewUncaughtException()) {
function_();
}
}
};
Icing
© 2014- Andrei Alexandrescu. Do not redistribute. 33 / 46
enum class ScopeGuardOnFail {};
template <typename FunctionType>
ScopeGuardForNewException<
typename std::decay<FunctionType>::type, true>
operator+(detail::ScopeGuardOnFail, FunctionType&& fn) {
return
ScopeGuardForNewException<
typename std::decay<FunctionType>::type, true>(
std::forward<FunctionType>(fn));
}
Cake Candles
© 2014- Andrei Alexandrescu. Do not redistribute. 34 / 46
enum class ScopeGuardOnSuccess {};
template <typename FunctionType>
ScopeGuardForNewException<
typename std::decay<FunctionType>::type, false>
operator+(detail::ScopeGuardOnSuccess, FunctionType&& fn) {
return
ScopeGuardForNewException<
typename std::decay<FunctionType>::type, false>(
std::forward<FunctionType>(fn));
}
Use Cases
© 2014- Andrei Alexandrescu. Do not redistribute. 35 / 46
Tracing
© 2014- Andrei Alexandrescu. Do not redistribute. 36 / 46
void login() {
SCOPE_FAIL {
cerr << "Failed to log in.n";
};
...
}
• User-displayable (unlike stack traces)
• Show only major failure points
Transactional Work
© 2014- Andrei Alexandrescu. Do not redistribute. 37 / 46
void buildFile(const string& name) {
auto tmp = name + ".deleteme";
auto f = fopen(tmp.data(), "w");
enforce(f, "...");
SCOPE_SUCCESS {
enforce(fclose(f) == 0, "...");
rename(tmp.data(). name.data());
};
SCOPE_FAIL {
fclose(f); // don’t care if fails
unlink(tmp.data());
};
...
}
Order Still Matters
© 2014- Andrei Alexandrescu. Do not redistribute. 38 / 46
void buildFile(const string& name) {
auto tmp = name + ".deleteme";
auto f = fopen(tmp.data(), "w");
enforce(f, "...");
SCOPE_FAIL { // PLANTED TOO EARLY!
fclose(f); // don’t care if fails
unlink(tmp.data());
};
SCOPE_SUCCESS {
enforce(fclose(f) == 0, "...");
rename(tmp.data(). name.data());
};
...
}
• Handler “sees” exceptions after planting
Please Note
© 2014- Andrei Alexandrescu. Do not redistribute. 39 / 46
Only SCOPE_SUCCESS
may throw
Postconditions
© 2014- Andrei Alexandrescu. Do not redistribute. 40 / 46
int string2int(const string& s) {
int r;
SCOPE_SUCCESS {
assert(int2string(r) == s);
};
...
return r;
}
Changing of the Guard
© 2014- Andrei Alexandrescu. Do not redistribute. 41 / 46
void process(char *const buf, size_t len) {
if (!len) return;
const auto save = buf[len - 1];
buf[len - 1] = 255;
SCOPE_EXIT { buf[len - 1] = save; };
for (auto p = buf;;) switch (auto c = *p++) {
...
}
}
Scoped Changes
© 2014- Andrei Alexandrescu. Do not redistribute. 42 / 46
bool g_sweeping;
void sweep() {
g_sweeping = true;
SCOPE_EXIT { g_sweeping = false; };
auto r = getRoot();
assert(r);
r->sweepAll();
}
No RAII Type? No Problem!
© 2014- Andrei Alexandrescu. Do not redistribute. 43 / 46
void fileTransact(int fd) {
enforce(flock(fd, LOCK_EX) == 0);
SCOPE_EXIT {
enforce(flock(fd, LOCK_UN) == 0);
};
...
}
• No need to add a type for occasional RAII
idioms
Remarks
© 2014- Andrei Alexandrescu. Do not redistribute. 44 / 46
• All examples taken from production code
• Declarative focus
◦ Declare contingency actions by context
• SCOPE_* more frequent than try in new code
• The latter remains in use for actual handling
• Flattened flow
• Order still matters
Summary
© 2014- Andrei Alexandrescu. Do not redistribute. 45 / 46
Summary
© 2014- Andrei Alexandrescu. Do not redistribute. 46 / 46
• SCOPE_EXIT
• SCOPE_FAILURE
• SCOPE_SUCCESS

More Related Content

What's hot

Static analysis and writing C/C++ of high quality code for embedded systems
Static analysis and writing C/C++ of high quality code for embedded systemsStatic analysis and writing C/C++ of high quality code for embedded systems
Static analysis and writing C/C++ of high quality code for embedded systemsAndrey Karpov
 
Basic Programs of C++
Basic Programs of C++Basic Programs of C++
Basic Programs of C++Bharat Kalia
 
Best Bugs from Games: Fellow Programmers' Mistakes
Best Bugs from Games: Fellow Programmers' MistakesBest Bugs from Games: Fellow Programmers' Mistakes
Best Bugs from Games: Fellow Programmers' MistakesAndrey Karpov
 
Better Code: Concurrency
Better Code: ConcurrencyBetter Code: Concurrency
Better Code: ConcurrencyPlatonov Sergey
 
Ee 3122 numerical methods and statistics sessional credit
Ee 3122 numerical methods and statistics sessional  creditEe 3122 numerical methods and statistics sessional  credit
Ee 3122 numerical methods and statistics sessional creditRaihan Bin-Mofidul
 
54602399 c-examples-51-to-108-programe-ee01083101
54602399 c-examples-51-to-108-programe-ee0108310154602399 c-examples-51-to-108-programe-ee01083101
54602399 c-examples-51-to-108-programe-ee01083101premrings
 
Tugas praktikukm pemrograman c++
Tugas praktikukm  pemrograman c++Tugas praktikukm  pemrograman c++
Tugas praktikukm pemrograman c++Dendi Riadi
 
C++ game development with oxygine
C++ game development with oxygineC++ game development with oxygine
C++ game development with oxyginecorehard_by
 
Network lap pgms 7th semester
Network lap pgms 7th semesterNetwork lap pgms 7th semester
Network lap pgms 7th semesterDOSONKA Group
 
Detection of errors and potential vulnerabilities in C and C++ code using the...
Detection of errors and potential vulnerabilities in C and C++ code using the...Detection of errors and potential vulnerabilities in C and C++ code using the...
Detection of errors and potential vulnerabilities in C and C++ code using the...Andrey Karpov
 
Oops pramming with examples
Oops pramming with examplesOops pramming with examples
Oops pramming with examplesSyed Khaleel
 

What's hot (20)

Static analysis and writing C/C++ of high quality code for embedded systems
Static analysis and writing C/C++ of high quality code for embedded systemsStatic analysis and writing C/C++ of high quality code for embedded systems
Static analysis and writing C/C++ of high quality code for embedded systems
 
Basic Programs of C++
Basic Programs of C++Basic Programs of C++
Basic Programs of C++
 
C++ TUTORIAL 7
C++ TUTORIAL 7C++ TUTORIAL 7
C++ TUTORIAL 7
 
Best Bugs from Games: Fellow Programmers' Mistakes
Best Bugs from Games: Fellow Programmers' MistakesBest Bugs from Games: Fellow Programmers' Mistakes
Best Bugs from Games: Fellow Programmers' Mistakes
 
Better Code: Concurrency
Better Code: ConcurrencyBetter Code: Concurrency
Better Code: Concurrency
 
C programs
C programsC programs
C programs
 
Ee 3122 numerical methods and statistics sessional credit
Ee 3122 numerical methods and statistics sessional  creditEe 3122 numerical methods and statistics sessional  credit
Ee 3122 numerical methods and statistics sessional credit
 
54602399 c-examples-51-to-108-programe-ee01083101
54602399 c-examples-51-to-108-programe-ee0108310154602399 c-examples-51-to-108-programe-ee01083101
54602399 c-examples-51-to-108-programe-ee01083101
 
Tugas praktikukm pemrograman c++
Tugas praktikukm  pemrograman c++Tugas praktikukm  pemrograman c++
Tugas praktikukm pemrograman c++
 
C++ TUTORIAL 8
C++ TUTORIAL 8C++ TUTORIAL 8
C++ TUTORIAL 8
 
C++ TUTORIAL 9
C++ TUTORIAL 9C++ TUTORIAL 9
C++ TUTORIAL 9
 
C++ TUTORIAL 4
C++ TUTORIAL 4C++ TUTORIAL 4
C++ TUTORIAL 4
 
C++ TUTORIAL 3
C++ TUTORIAL 3C++ TUTORIAL 3
C++ TUTORIAL 3
 
C++ TUTORIAL 6
C++ TUTORIAL 6C++ TUTORIAL 6
C++ TUTORIAL 6
 
C++ TUTORIAL 1
C++ TUTORIAL 1C++ TUTORIAL 1
C++ TUTORIAL 1
 
C++ TUTORIAL 10
C++ TUTORIAL 10C++ TUTORIAL 10
C++ TUTORIAL 10
 
C++ game development with oxygine
C++ game development with oxygineC++ game development with oxygine
C++ game development with oxygine
 
Network lap pgms 7th semester
Network lap pgms 7th semesterNetwork lap pgms 7th semester
Network lap pgms 7th semester
 
Detection of errors and potential vulnerabilities in C and C++ code using the...
Detection of errors and potential vulnerabilities in C and C++ code using the...Detection of errors and potential vulnerabilities in C and C++ code using the...
Detection of errors and potential vulnerabilities in C and C++ code using the...
 
Oops pramming with examples
Oops pramming with examplesOops pramming with examples
Oops pramming with examples
 

Similar to 10 declarative-control-flow.handouts

CUDA Tutorial 01 : Say Hello to CUDA : Notes
CUDA Tutorial 01 : Say Hello to CUDA : NotesCUDA Tutorial 01 : Say Hello to CUDA : Notes
CUDA Tutorial 01 : Say Hello to CUDA : NotesSubhajit Sahu
 
Open Cv 2005 Q4 Tutorial
Open Cv 2005 Q4 TutorialOpen Cv 2005 Q4 Tutorial
Open Cv 2005 Q4 Tutorialantiw
 
Painless JavaScript Testing with Jest
Painless JavaScript Testing with JestPainless JavaScript Testing with Jest
Painless JavaScript Testing with JestMichał Pierzchała
 
Why should we use SIMPLE FACTORY pattern even when we have one class only?
Why should we use SIMPLE FACTORY pattern even when we have one class only?Why should we use SIMPLE FACTORY pattern even when we have one class only?
Why should we use SIMPLE FACTORY pattern even when we have one class only?Rafal Ksiazek
 
Threaded Programming
Threaded ProgrammingThreaded Programming
Threaded ProgrammingSri Prasanna
 
Three, no, Four Cool Things About D
Three, no, Four Cool Things About DThree, no, Four Cool Things About D
Three, no, Four Cool Things About DAndrei Alexandrescu
 
ES6 - Next Generation Javascript
ES6 - Next Generation JavascriptES6 - Next Generation Javascript
ES6 - Next Generation JavascriptRamesh Nair
 
Swift - One step forward from Obj-C
Swift -  One step forward from Obj-CSwift -  One step forward from Obj-C
Swift - One step forward from Obj-CNissan Tsafrir
 
Moving from Jenkins 1 to 2 declarative pipeline adventures
Moving from Jenkins 1 to 2 declarative pipeline adventuresMoving from Jenkins 1 to 2 declarative pipeline adventures
Moving from Jenkins 1 to 2 declarative pipeline adventuresFrits Van Der Holst
 
Top 10 bugs in C++ open source projects, checked in 2016
Top 10 bugs in C++ open source projects, checked in 2016Top 10 bugs in C++ open source projects, checked in 2016
Top 10 bugs in C++ open source projects, checked in 2016PVS-Studio
 
FrontDays #3. Иван Федяев, Эволюция JavaScript. Обзор нововведений ECMAScript 6
FrontDays #3. Иван Федяев, Эволюция JavaScript. Обзор нововведений ECMAScript 6FrontDays #3. Иван Федяев, Эволюция JavaScript. Обзор нововведений ECMAScript 6
FrontDays #3. Иван Федяев, Эволюция JavaScript. Обзор нововведений ECMAScript 6FrontDays
 
Build 2016 - B880 - Top 6 Reasons to Move Your C++ Code to Visual Studio 2015
Build 2016 - B880 - Top 6 Reasons to Move Your C++ Code to Visual Studio 2015Build 2016 - B880 - Top 6 Reasons to Move Your C++ Code to Visual Studio 2015
Build 2016 - B880 - Top 6 Reasons to Move Your C++ Code to Visual Studio 2015Windows Developer
 
Programming Sideways: Asynchronous Techniques for Android
Programming Sideways: Asynchronous Techniques for AndroidProgramming Sideways: Asynchronous Techniques for Android
Programming Sideways: Asynchronous Techniques for AndroidEmanuele Di Saverio
 
JavaScript Futures—ES2017 and Beyond
JavaScript Futures—ES2017 and BeyondJavaScript Futures—ES2017 and Beyond
JavaScript Futures—ES2017 and BeyondJeff Strauss
 
Pablo Magaz | ECMAScript 2018 y más allá | Codemotion Madrid 2018
Pablo Magaz | ECMAScript 2018 y más allá | Codemotion Madrid 2018Pablo Magaz | ECMAScript 2018 y más allá | Codemotion Madrid 2018
Pablo Magaz | ECMAScript 2018 y más allá | Codemotion Madrid 2018Codemotion
 
Verilog Tasks & Functions
Verilog Tasks & FunctionsVerilog Tasks & Functions
Verilog Tasks & Functionsanand hd
 
Дмитрий Верескун «Синтаксический сахар C#»
Дмитрий Верескун «Синтаксический сахар C#»Дмитрий Верескун «Синтаксический сахар C#»
Дмитрий Верескун «Синтаксический сахар C#»SpbDotNet Community
 

Similar to 10 declarative-control-flow.handouts (20)

CUDA Tutorial 01 : Say Hello to CUDA : Notes
CUDA Tutorial 01 : Say Hello to CUDA : NotesCUDA Tutorial 01 : Say Hello to CUDA : Notes
CUDA Tutorial 01 : Say Hello to CUDA : Notes
 
Open Cv 2005 Q4 Tutorial
Open Cv 2005 Q4 TutorialOpen Cv 2005 Q4 Tutorial
Open Cv 2005 Q4 Tutorial
 
Painless JavaScript Testing with Jest
Painless JavaScript Testing with JestPainless JavaScript Testing with Jest
Painless JavaScript Testing with Jest
 
Why should we use SIMPLE FACTORY pattern even when we have one class only?
Why should we use SIMPLE FACTORY pattern even when we have one class only?Why should we use SIMPLE FACTORY pattern even when we have one class only?
Why should we use SIMPLE FACTORY pattern even when we have one class only?
 
Threaded Programming
Threaded ProgrammingThreaded Programming
Threaded Programming
 
Three, no, Four Cool Things About D
Three, no, Four Cool Things About DThree, no, Four Cool Things About D
Three, no, Four Cool Things About D
 
ES6 - Next Generation Javascript
ES6 - Next Generation JavascriptES6 - Next Generation Javascript
ES6 - Next Generation Javascript
 
Swift - One step forward from Obj-C
Swift -  One step forward from Obj-CSwift -  One step forward from Obj-C
Swift - One step forward from Obj-C
 
Moving from Jenkins 1 to 2 declarative pipeline adventures
Moving from Jenkins 1 to 2 declarative pipeline adventuresMoving from Jenkins 1 to 2 declarative pipeline adventures
Moving from Jenkins 1 to 2 declarative pipeline adventures
 
Top 10 bugs in C++ open source projects, checked in 2016
Top 10 bugs in C++ open source projects, checked in 2016Top 10 bugs in C++ open source projects, checked in 2016
Top 10 bugs in C++ open source projects, checked in 2016
 
FrontDays #3. Иван Федяев, Эволюция JavaScript. Обзор нововведений ECMAScript 6
FrontDays #3. Иван Федяев, Эволюция JavaScript. Обзор нововведений ECMAScript 6FrontDays #3. Иван Федяев, Эволюция JavaScript. Обзор нововведений ECMAScript 6
FrontDays #3. Иван Федяев, Эволюция JavaScript. Обзор нововведений ECMAScript 6
 
ECMAScript 2015 Tips & Traps
ECMAScript 2015 Tips & TrapsECMAScript 2015 Tips & Traps
ECMAScript 2015 Tips & Traps
 
Build 2016 - B880 - Top 6 Reasons to Move Your C++ Code to Visual Studio 2015
Build 2016 - B880 - Top 6 Reasons to Move Your C++ Code to Visual Studio 2015Build 2016 - B880 - Top 6 Reasons to Move Your C++ Code to Visual Studio 2015
Build 2016 - B880 - Top 6 Reasons to Move Your C++ Code to Visual Studio 2015
 
Php 5.6
Php 5.6Php 5.6
Php 5.6
 
Programming Sideways: Asynchronous Techniques for Android
Programming Sideways: Asynchronous Techniques for AndroidProgramming Sideways: Asynchronous Techniques for Android
Programming Sideways: Asynchronous Techniques for Android
 
JavaScript Futures—ES2017 and Beyond
JavaScript Futures—ES2017 and BeyondJavaScript Futures—ES2017 and Beyond
JavaScript Futures—ES2017 and Beyond
 
Pablo Magaz | ECMAScript 2018 y más allá | Codemotion Madrid 2018
Pablo Magaz | ECMAScript 2018 y más allá | Codemotion Madrid 2018Pablo Magaz | ECMAScript 2018 y más allá | Codemotion Madrid 2018
Pablo Magaz | ECMAScript 2018 y más allá | Codemotion Madrid 2018
 
Verilog Tasks & Functions
Verilog Tasks & FunctionsVerilog Tasks & Functions
Verilog Tasks & Functions
 
Дмитрий Верескун «Синтаксический сахар C#»
Дмитрий Верескун «Синтаксический сахар C#»Дмитрий Верескун «Синтаксический сахар C#»
Дмитрий Верескун «Синтаксический сахар C#»
 
CppTutorial.ppt
CppTutorial.pptCppTutorial.ppt
CppTutorial.ppt
 

More from Andrei Alexandrescu

More from Andrei Alexandrescu (6)

Dconf2015 d2 t4
Dconf2015 d2 t4Dconf2015 d2 t4
Dconf2015 d2 t4
 
Dconf2015 d2 t3
Dconf2015 d2 t3Dconf2015 d2 t3
Dconf2015 d2 t3
 
DConf 2013 Opening Keynote by Walter Bright
DConf 2013 Opening Keynote by Walter BrightDConf 2013 Opening Keynote by Walter Bright
DConf 2013 Opening Keynote by Walter Bright
 
Three Optimization Tips for C++
Three Optimization Tips for C++Three Optimization Tips for C++
Three Optimization Tips for C++
 
Three Optimization Tips for C++
Three Optimization Tips for C++Three Optimization Tips for C++
Three Optimization Tips for C++
 
Generic Programming Galore Using D
Generic Programming Galore Using DGeneric Programming Galore Using D
Generic Programming Galore Using D
 

10 declarative-control-flow.handouts

  • 1. © 2014- Andrei Alexandrescu. Do not redistribute. 1 / 46 Declarative Control Flow Prepared for NDC Oslo 2014 Andrei Alexandrescu, Ph.D. andrei@erdani.com Agenda © 2014- Andrei Alexandrescu. Do not redistribute. 2 / 46 • Motivation • Implementation • Use cases
  • 2. © 2014- Andrei Alexandrescu. Do not redistribute. 3 / 46 action cleanup next rollback C © 2014- Andrei Alexandrescu. Do not redistribute. 4 / 46 if ( action ) { if (! next ) { rollback } cleanup }
  • 3. C++ © 2014- Andrei Alexandrescu. Do not redistribute. 5 / 46 class RAII { RAII() { action } ~RAII() { cleanup } }; ... RAII raii; try { next } catch (...) { rollback throw; } Java, C# © 2014- Andrei Alexandrescu. Do not redistribute. 6 / 46 action try { next } catch (Exception e) { rollback throw e; } finally { cleanup }
  • 4. Go © 2014- Andrei Alexandrescu. Do not redistribute. 7 / 46 result, error := action if error != nil { defer cleanup if ! next rollback } Composition
  • 5. C © 2014- Andrei Alexandrescu. Do not redistribute. 9 / 46 if ( action1 ) { if ( action2 ) { if (! next2 ) { rollback2 rollback1 } cleanup2 } else { rollback1 } cleanup1 } C (Pros Only) © 2014- Andrei Alexandrescu. Do not redistribute. 10 / 46 if (! action1 ) { goto done; } if (! action2 ) { goto r1; } if (! next2 ) { goto r2; } cleanup2 goto c1; r2: rollback2 cleanup2 r1: rollback1 c1: cleanup1 done: ;
  • 6. C++ © 2014- Andrei Alexandrescu. Do not redistribute. 11 / 46 class RAII1 { RAII1() { action1 } ~RAII1() { cleanup1 } }; class RAII2 { RAII2() { action2 } ~RAII2() { cleanup2 } }; ... C++ © 2014- Andrei Alexandrescu. Do not redistribute. 12 / 46 RAII1 raii1; try { RAII2 raii2; try { next2 } catch (...) { rollback2 throw; } } catch (...) { rollback1 throw; }
  • 7. Java, C# © 2014- Andrei Alexandrescu. Do not redistribute. 13 / 46 action1 try { action2 try { next2 } catch (Exception e) { rollback2 throw e; } finally { cleanup2 } } catch (Exception e) { rollback1 throw e; } finally { cleanup1 } Go © 2014- Andrei Alexandrescu. Do not redistribute. 14 / 46 result1, error := action1 if error != nil { defer cleanup1 result2, error := action2 if error != nil { defer cleanup2 if ! next2 rollback2 } else { rollback2 } }
  • 8. © 2014- Andrei Alexandrescu. Do not redistribute. 15 / 46 Explicit Control Flow = Fail Declarative Programming © 2014- Andrei Alexandrescu. Do not redistribute. 16 / 46 • Focus on stating needed accomplishments • As opposed to describing steps • Control flow typically minimal/absent • Execution is implicit, not explicit • Examples: SQL, regex, make, config,. . . • Let’s take a page from their book!
  • 9. According to Seinfeld © 2014- Andrei Alexandrescu. Do not redistribute. 17 / 46 Declarative: airplane ticket Imperative: what the pilot does Surprising Insight © 2014- Andrei Alexandrescu. Do not redistribute. 18 / 46 • Consider bona fide RAII with destructors: States needed accomplishment? Implicit execution? Control flow minimal? • RAII is declarative programming!
  • 10. More RAII: ScopeGuard © 2014- Andrei Alexandrescu. Do not redistribute. 19 / 46 • Also declarative • Less syntactic baggage than cdtors • Flow is “automated” through placement • Macro SCOPE_EXIT raises it to pseudo-statement status Pseudo-Statement (NDC workshop re- cap!) © 2014- Andrei Alexandrescu. Do not redistribute. 20 / 46 namespace detail { enum class ScopeGuardOnExit {}; template <typename Fun> ScopeGuard<Fun> operator+(ScopeGuardOnExit, Fun&& fn) { return ScopeGuard<Fun>(std::forward<Fun>(fn)); } } #define SCOPE_EXIT auto ANONYMOUS_VARIABLE(SCOPE_EXIT_STATE) = ::detail::ScopeGuardOnExit() + [&]()
  • 11. Preprocessor Trick (NDC workshop re- cap!) © 2014- Andrei Alexandrescu. Do not redistribute. 21 / 46 #define CONCATENATE_IMPL(s1, s2) s1##s2 #define CONCATENATE(s1, s2) CONCATENATE_IMPL(s1, s2) #ifdef __COUNTER__ #define ANONYMOUS_VARIABLE(str) CONCATENATE(str, __COUNTER__) #else #define ANONYMOUS_VARIABLE(str) CONCATENATE(str, __LINE__) #endif Use (NDC workshop recap!) © 2014- Andrei Alexandrescu. Do not redistribute. 22 / 46 void fun() { char name[] = "/tmp/deleteme.XXXXXX"; auto fd = mkstemp(name); SCOPE_EXIT { fclose(fd); unlink(name); }; auto buf = malloc(1024 * 1024); SCOPE_EXIT { free(buf); }; ... use fd and buf ... } (if no “;” after lambda, error message is meh)
  • 12. Painfully Close to Ideal! © 2014- Andrei Alexandrescu. Do not redistribute. 23 / 46 action1 SCOPE_EXIT { cleanup1 }; SCOPE_FAIL { rollback1 }; // nope action2 SCOPE_EXIT { cleanup2 }; SCOPE_FAIL { rollback2 }; // nope next2 • Note: slide plagiated from C&B 2012 One more for completeness © 2014- Andrei Alexandrescu. Do not redistribute. 24 / 46 action SCOPE_SUCCESS { celebrate }; next • Powerful flow-declarative trifecta! • Do not specify flow • Instead declare circumstances and goals
  • 13. © 2014- Andrei Alexandrescu. Do not redistribute. 25 / 46 Can be implemented today on ALL major compilers © 2014- Andrei Alexandrescu. Do not redistribute. 26 / 46 May become 100% portable: http://isocpp.org/files/papers/N3614.pdf
  • 14. Credits © 2014- Andrei Alexandrescu. Do not redistribute. 27 / 46 • Evgeny Panasyuk: compiler-specific bits github.com/panaseleus/stack_unwinding • Daniel Marinescu: folly implementation github.com/facebook/folly Underpinnings © 2014- Andrei Alexandrescu. Do not redistribute. 28 / 46 class UncaughtExceptionCounter { int getUncaughtExceptionCount() noexcept; int exceptionCount_; public: UncaughtExceptionCounter() : exceptionCount_(getUncaughtExceptionCount()) { } bool isNewUncaughtException() noexcept { return getUncaughtExceptionCount() > exceptionCount_; } }; • Only detail left: getUncaughtExceptionCount()
  • 15. gcc/clang © 2014- Andrei Alexandrescu. Do not redistribute. 29 / 46 inline int UncaughtExceptionCounter:: getUncaughtExceptionCount() noexcept { // __cxa_get_globals returns a __cxa_eh_globals* // (defined in unwind-cxx.h). // The offset below returns // __cxa_eh_globals::uncaughtExceptions. return *(reinterpret_cast<int*>( static_cast<char*>( static_cast<void*>( __cxxabiv1::__cxa_get_globals())) + sizeof(void*))); } gcc/clang © 2014- Andrei Alexandrescu. Do not redistribute. 30 / 46 namespace __cxxabiv1 { // defined in unwind-cxx.h from from libstdc++ struct __cxa_eh_globals; // declared in cxxabi.h from libstdc++-v3 extern "C" __cxa_eh_globals* __cxa_get_globals() noexcept; }
  • 16. MSVC 8.0+ © 2014- Andrei Alexandrescu. Do not redistribute. 31 / 46 struct _tiddata; extern "C" _tiddata* _getptd(); inline int UncaughtExceptionCounter:: getUncaughtExceptionCount() noexcept { // _getptd() returns a _tiddata* // (defined in mtdll.h). // The offset below returns // _tiddata::_ProcessingThrow. return *(reinterpret_cast<int*>(static_cast<char*>( static_cast<void*>(_getptd())) + sizeof(void*) * 28 + 0x4 * 8)); } Layering © 2014- Andrei Alexandrescu. Do not redistribute. 32 / 46 template <typename FunctionType, bool executeOnException> class ScopeGuardForNewException { FunctionType function_; UncaughtExceptionCounter ec_; public: explicit ScopeGuardForNewException(const FunctionType& fn) : function_(fn) { } explicit ScopeGuardForNewException(FunctionType&& fn) : function_(std::move(fn)) { } ~ScopeGuardForNewException() noexcept(executeOnException) { if (executeOnException == ec_.isNewUncaughtException()) { function_(); } } };
  • 17. Icing © 2014- Andrei Alexandrescu. Do not redistribute. 33 / 46 enum class ScopeGuardOnFail {}; template <typename FunctionType> ScopeGuardForNewException< typename std::decay<FunctionType>::type, true> operator+(detail::ScopeGuardOnFail, FunctionType&& fn) { return ScopeGuardForNewException< typename std::decay<FunctionType>::type, true>( std::forward<FunctionType>(fn)); } Cake Candles © 2014- Andrei Alexandrescu. Do not redistribute. 34 / 46 enum class ScopeGuardOnSuccess {}; template <typename FunctionType> ScopeGuardForNewException< typename std::decay<FunctionType>::type, false> operator+(detail::ScopeGuardOnSuccess, FunctionType&& fn) { return ScopeGuardForNewException< typename std::decay<FunctionType>::type, false>( std::forward<FunctionType>(fn)); }
  • 18. Use Cases © 2014- Andrei Alexandrescu. Do not redistribute. 35 / 46 Tracing © 2014- Andrei Alexandrescu. Do not redistribute. 36 / 46 void login() { SCOPE_FAIL { cerr << "Failed to log in.n"; }; ... } • User-displayable (unlike stack traces) • Show only major failure points
  • 19. Transactional Work © 2014- Andrei Alexandrescu. Do not redistribute. 37 / 46 void buildFile(const string& name) { auto tmp = name + ".deleteme"; auto f = fopen(tmp.data(), "w"); enforce(f, "..."); SCOPE_SUCCESS { enforce(fclose(f) == 0, "..."); rename(tmp.data(). name.data()); }; SCOPE_FAIL { fclose(f); // don’t care if fails unlink(tmp.data()); }; ... } Order Still Matters © 2014- Andrei Alexandrescu. Do not redistribute. 38 / 46 void buildFile(const string& name) { auto tmp = name + ".deleteme"; auto f = fopen(tmp.data(), "w"); enforce(f, "..."); SCOPE_FAIL { // PLANTED TOO EARLY! fclose(f); // don’t care if fails unlink(tmp.data()); }; SCOPE_SUCCESS { enforce(fclose(f) == 0, "..."); rename(tmp.data(). name.data()); }; ... } • Handler “sees” exceptions after planting
  • 20. Please Note © 2014- Andrei Alexandrescu. Do not redistribute. 39 / 46 Only SCOPE_SUCCESS may throw Postconditions © 2014- Andrei Alexandrescu. Do not redistribute. 40 / 46 int string2int(const string& s) { int r; SCOPE_SUCCESS { assert(int2string(r) == s); }; ... return r; }
  • 21. Changing of the Guard © 2014- Andrei Alexandrescu. Do not redistribute. 41 / 46 void process(char *const buf, size_t len) { if (!len) return; const auto save = buf[len - 1]; buf[len - 1] = 255; SCOPE_EXIT { buf[len - 1] = save; }; for (auto p = buf;;) switch (auto c = *p++) { ... } } Scoped Changes © 2014- Andrei Alexandrescu. Do not redistribute. 42 / 46 bool g_sweeping; void sweep() { g_sweeping = true; SCOPE_EXIT { g_sweeping = false; }; auto r = getRoot(); assert(r); r->sweepAll(); }
  • 22. No RAII Type? No Problem! © 2014- Andrei Alexandrescu. Do not redistribute. 43 / 46 void fileTransact(int fd) { enforce(flock(fd, LOCK_EX) == 0); SCOPE_EXIT { enforce(flock(fd, LOCK_UN) == 0); }; ... } • No need to add a type for occasional RAII idioms Remarks © 2014- Andrei Alexandrescu. Do not redistribute. 44 / 46 • All examples taken from production code • Declarative focus ◦ Declare contingency actions by context • SCOPE_* more frequent than try in new code • The latter remains in use for actual handling • Flattened flow • Order still matters
  • 23. Summary © 2014- Andrei Alexandrescu. Do not redistribute. 45 / 46 Summary © 2014- Andrei Alexandrescu. Do not redistribute. 46 / 46 • SCOPE_EXIT • SCOPE_FAILURE • SCOPE_SUCCESS