SlideShare a Scribd company logo
Asynchronous, yet readable, code
Kamil Witecki
November 16, 2016
Subject of discussion
(a) Callbacks
Subject of discussion
(a) Callbacks
(b) Promises
Subject of discussion
(a) Callbacks
(b) Promises
(c) Coroutines
Callbacks
Callbacks are simple but lacking. Do not use them.
Promises
Promises bring more control and structure to our code.
Coroutines
Coroutines provide best possible results and are our choice.
Writing code is easy
You write what you have on mind. And understand it.
https://en.wikipedia.org/wiki/Scribe#/media/File:Escribano.jpg
Maintenance is hell
https://en.wikipedia.org/wiki/Scribe#/media/File:Escribano.jpg [1]
Example
//avoid allocating temporary int
void countZeros ( std : : vector <void∗>& a , int ∗ out )
{
out = 0;
for ( auto i = begin ( a ) ; i != end ( a ) ; ++i ) {
i f (!∗ i ) ++out ;
}
}
Example
//avoid allocating temporary int
void countZeros ( std : : vector <void∗>& a , int ∗ out )
{
out = 0;
for ( auto i = begin ( a ) ; i != end ( a ) ; ++i ) {
i f (!∗ i ) ++out ;
}
}
template<typename Container >
auto c o u n t n u l l p t r s ( Container const& cont ) −>
std : : s i z e t
{
return count ( begin ( cont ) , end ( cont ) , n u l l p t r ) ;
}
Area of interest - asynchronous programming
Synchronous
Your code
Other code
Eg. kernel
Idle
Start operation
Complete operation
Start operation
Complete operation
Executes
other code
Operation results
wait for processing
Asynchronous
Your code
Other code
Eg. kernel
Case study: conversation I
We will focus on a example like:
e(d(c(b(a(params)))))
What in synchronous code gets as simple as:
e (d( c (b( a ( params ) ) ) ) )
Or:
resultFromA = a ( params )
resultFromB = b( resultFromA )
resultFromC = c ( resultFromB )
resultFromD = d( resultFromC )
resultFromE = e ( resultFromD )
Case study: conversation II
Case study: ïŹ‚ow control
Next we will be looking into code that reads two ïŹles and compares content:
a = io.open ( ’a.txt’)
a data = a : read ( ’a’)
b = io.open ( ’b.txt’)
b data = b : read ( ’a’)
compare ( a data , b data )
Case study: debugging
Last but not least - we will be checking how errors are manifested.
Approach #1: callback
C++:
void r e a d h a n d l e r ( e r r o r c o d e const& ec ,
s i z e t bytes ) { . . . }
read ( . . . , r e a d h a n d l e r ) ;
Lua:
function r e a d h a n d l e r ( data ) end
socket : on ("data" , r e a d h a n d l e r )
JavaScript:
function r e a d h a n d l e r ( data ) {}
socket . on ("data" , r e a d h a n d l e r ) ;
Approach #1: pitfall
a ( params , function ( resultFromA , e r r )
i f ( ! e r r ) then return end
b( resultFromA , function ( resultFromB , e r r )
i f ( ! e r r ) then return end
c ( resultFromB , function ( resultFromC , e r r )
i f ( ! e r r ) then return end
d( resultFromC , function ( resultFromD , e r r )
i f ( ! e r r ) then return end
e ( resultFromD , function ( resultFromE , e r r )
// . .
end)
end)
end)
end)
end)
Approach #1: phony solution
a ( params , HandleResultsOfA ) ;
HandleResultsOfA ( resultFromA , e r r ) {
i f ( ! e r r ) return ;
b( resultFromA , HandleResultsOfB ) ;
}
HandleResultsOfB ( resultFromB , e r r ) {
i f ( ! e r r ) return ;
c ( resultFromB , HandleResultsOfC ) ;
}
HandleResultsOfC ( resultFromC , e r r ) {
i f ( ! e r r ) return ;
d( resultFromC , HandleResultsOfD ) ;
}
HandleResultsOfD ( resultFromD , e r r ) {
i f ( ! e r r ) return ;
Approach #1: how I see it
Approach #1: debugging I
1 f s . s t a t ("1.txt" , function () {
2 f s . s t a t ("2.txt" , function () {
3 //obvious error
4 f s . s t a t ( function (){} , function () {})
5 })
6 })
Approach #1: debugging II
Result is ok, error can be easily spotted:
>node t e s t . j s
f s . j s :783
binding . s t a t ( pathModule . makeLong ( path ) , req ) ;
ˆ
TypeError : path must be a s t r i n g
at TypeError ( n a t i v e )
at Object . f s . s t a t ( f s . j s :783:11)
at t e s t . j s : 4 : 8
at FSReqWrap . oncomplete ( f s . j s : 9 5 : 1 5 )
test.js:4 is:
f s . s t a t ( function (){} , function () {})
Approach #1: say goodbye to your stacktrace I
What if we use same function in multiple places?
1 var f s = r e q u i r e ( ’fs’ ) ;
2 function bug ( content , cont ) {
3 f s . w r i t e F i l e ("config.json" , content ,
4 function () { f s . s t a t ("config.json" , cont ) ;
5 } ) ;
6 }
7
8 bug ("{}" , "wrong")
Approach #1: say goodbye to your stacktrace II
Result:
>node t e s t . j s
throw new TypeError ( ’ c a l l b a c k must be a function ’ ) ;
TypeError : c a l l b a c k must be a f u n c t i o n
at makeCallback ( f s . j s : 7 8 : 1 1 )
at Object . f s . s t a t ( f s . j s :826:14)
at t e s t . j s : 4 : 2 0
at FSReqWrap . oncomplete ( f s . j s : 8 2 : 1 5 )
test.js:4 is:
function () { f s . s t a t ("config.json" , cont ) ;
While there error is in test.js:8:
bug ("{}" , "wrong")
Approach #1: What?
Approach #1: pros and cons
Pros
Easy to use,
Approach #1: pros and cons
Pros
Easy to use,
Integrated by default
Approach #1: pros and cons
Pros
Easy to use,
Integrated by default
Approach #1: pros and cons
Pros
Easy to use,
Integrated by default
Cons
Degrades to callback hell quickly
Approach #1: pros and cons
Pros
Easy to use,
Integrated by default
Cons
Degrades to callback hell quickly
Makes stacktraces unusable
Approach #1: pros and cons
Pros
Easy to use,
Integrated by default
Cons
Degrades to callback hell quickly
Makes stacktraces unusable
Does not address more complex ïŹ‚ow control scenarios
Approach #1: pros and cons
Pros
Easy to use,
Integrated by default
Cons
Degrades to callback hell quickly
Makes stacktraces unusable
Does not address more complex ïŹ‚ow control scenarios
Approach #1: pros and cons
Pros
Easy to use,
Integrated by default
Cons
Degrades to callback hell quickly
Makes stacktraces unusable
Does not address more complex ïŹ‚ow control scenarios
Approach #2: Promises
Abstract model of asynchronous computation results.
Pending
.then(fulfillCallback,...)
.then(
, rejectCallback)
.catch()
Resolved
Rejected
Cancelled
OnValue
OnError
OnCancel
OnValue
OnError
(no actions)
(action)
(recovery)
(no recovery)
Approach #2: Case study I
Do you remember callback hell?
a ( params , function ( resultFromA , e r r )
i f ( ! e r r ) then return end
b( resultFromA , function ( resultFromB , e r r )
i f ( ! e r r ) then return end
c ( resultFromB , function ( resultFromC , e r r )
i f ( ! e r r ) then return end
d( resultFromC , function ( resultFromD , e r r )
i f ( ! e r r ) then return end
e ( resultFromD , function ( resultFromE , e r r )
// . .
end)
end)
end)
end)
end)
Approach #2: Case study II
Promises let you write it following way:
a ( params )
: next ( function ( resultFromA )
return b( resultFromA ) end)
: next ( function ( resultFromB )
return c ( resultFromB ) end)
: next ( function ( resultFromC )
return d( resultFromC ) end)
: next ( function ( resultFromD )
. . . end) .
Approach #2: Case study III
With a bit of imagination you can read it as:
a ( params )
--:next(function(resultFromA) return
b( resultFromA ) -- end)
--:next(function(resultFromB) return
c ( resultFromB ) -- end)
--:next(function(resultFromC) return
d( resultFromC ) -- end)
--:next(function(resultFromD)
. . . --end)
Approach #2: ïŹ‚ow control
Promises are abstract model of computation. Therefore it is possible to build
ïŹ‚ow control with them. For example:
c(a(paramsOfA), b(paramsOfB))
becomes:
l o c a l a = f s . readAsync ("a.txt")
l o c a l b = f s . readAsync ("b.txt")
d e f e r r e d . a l l ({a , b } ) : next ( function ( r e s u l t s )
return c ( r e s u l t s [ 0 ] , r e s u l t s [ 1 ] )
end )
Approach #2: What about callstacks? I
1 var Promise = r e q u i r e ("bluebird" ) ;
2 var f s = r e q u i r e ( ’fs’ ) ;
3 Promise . p r o m i s i f y A l l ( f s ) ;
4 function b( f i l e ) {return function ()
5 {return f s . statAsync ( f i l e )}}
6 f s . statAsync ("1.txt")
7 . then (b("2.txt" ))
8 . then (b( undefined ))
Approach #2: It’s a trap!
1 var Promise = r e q u i r e ("bluebird" ) ;
2 var f s = r e q u i r e ( ’fs’ ) ;
3 Promise . p r o m i s i f y A l l ( f s ) ;
4 function b( f i l e ) {return function ()
5 {return f s . statAsync ( f i l e )}}
6 f s . statAsync ("1.txt")
7 . then (b("2.txt" ))
8 . then (b( undefined ))
Approach #2: What about callstacks? II
Still not so good:
Unhandled r e j e c t i o n TypeError : path must be a s t r i n g
at TypeError ( n a t i v e )
at Object . f s . s t a t ( f s . j s : 7 8 3 : 1 1 )
at Object . t r y C a t c h e r ( node modules b l u e b i r d  j s  r e l e a s e  u t i l . j s : 1 6 : 2 3 )
at Object . r e t [ as statAsync ] ( e v a l at <anonymous> ( node modules b l u e b i r d  j s  r e l e a s e  p r o m i s i f y . j s : 1 8 4 : 1 2 ) , <a
at t e s t . j s : 5 : 1 3
at t r y C a t c h e r ( node modules b l u e b i r d  j s  r e l e a s e  u t i l . j s : 1 6 : 2 3 )
at Promise . settlePromiseFromHandler ( node modules b l u e b i r d  j s  r e l e a s e promise . j s : 5 0 9 : 3 1 )
at Promise . s e t t l e P r o m i s e ( node modules b l u e b i r d  j s  r e l e a s e promise . j s : 5 6 6 : 1 8 )
at Promise . s e t t l e P r o m i s e 0 ( node modules b l u e b i r d  j s  r e l e a s e promise . j s : 6 1 1 : 1 0 )
at Promise . s e t t l e P r o m i s e s ( node modules b l u e b i r d  j s  r e l e a s e promise . j s : 6 9 0 : 1 8 )
at Promise . f u l f i l l ( node modules b l u e b i r d  j s  r e l e a s e promise . j s : 6 3 5 : 1 8 )
at node modules b l u e b i r d  j s  r e l e a s e nodeback . j s : 4 2 : 2 1
at FSReqWrap . oncomplete ( f s . j s : 9 5 : 1 5 )
test.js:4-5
function b( f i l e ) { return function ()
{ return f s . statAsync ( f i l e )}}
Approach #2: pros and cons
Pros
Code structure and business logic are more coherent,
Approach #2: pros and cons
Pros
Code structure and business logic are more coherent,
Provide abstraction of ïŹ‚ow control
Approach #2: pros and cons
Pros
Code structure and business logic are more coherent,
Provide abstraction of ïŹ‚ow control
Approach #2: pros and cons
Pros
Code structure and business logic are more coherent,
Provide abstraction of ïŹ‚ow control
Cons
Some boiler plate still needed for each call
Approach #2: pros and cons
Pros
Code structure and business logic are more coherent,
Provide abstraction of ïŹ‚ow control
Cons
Some boiler plate still needed for each call
Makes stacktraces unusable
Approach #2: pros and cons
Pros
Code structure and business logic are more coherent,
Provide abstraction of ïŹ‚ow control
Cons
Some boiler plate still needed for each call
Makes stacktraces unusable
Approach #2: pros and cons
Pros
Code structure and business logic are more coherent,
Provide abstraction of ïŹ‚ow control
Cons
Some boiler plate still needed for each call
Makes stacktraces unusable
Approach #3: Coroutines
http://www.boost.org/doc/libs/1 60 0/libs/coroutine/doc/html/coroutine/intro.html [2]
Approach #3: Case study I
We will look, again, at e(d(c(b(a(params))))), now with coroutines!
coroutine.wrap ( function ()
resultFromA = a ( params )
resultFromB = b( resultFromA )
resultFromC = c ( resultFromB )
resultFromD = d( resultFromC )
resultFromE = e ( resultFromD )
end ) ( )
Approach #3: ïŹ‚ow control
Coroutines allow to build ïŹ‚ow control with them, too. For example:
c(a(paramsOfA), b(paramsOfB))
becomes:
coroutine.wrap ( function ()
a , b = c o r o s p l i t (
function () return f s. re ad As yn c ( ’a.txt’) end ,
function () return f s. re ad As yn c ( ’b.txt’) end)
c (a , b)
end ) ( )
Approach #3: What about callstacks? I
1 local f s = require ’coro-fs’
2 function bug ()
3 f s . s t a t ("2.txt")
4 return f s . s t a t ( function () print "x" end)
5 end
6 coroutine.wrap ( function () xpcall ( function ()
7 f s . s t a t ("1.txt")
8 bug ()
9 end ,
10 function ( e ) print ( debug.traceback ( e ) ) ; return e end)
11 end ) ( )
Approach #3: What about callstacks? II
> l u v i t . exe c o r o u t i n e s . lua
deps / coro−f s . lua : 4 4 : bad argument #1 to ’ f s s t a t ’
( s t r i n g expected , got f u n c t i o n )
stack traceback :
t e s t . lua : 1 0 : in f u n c t i o n <t e s t . lua :10>
[C ] : in f u n c t i o n ’ f s s t a t ’
deps / coro−f s . lua : 4 4 : in f u n c t i o n ’ bug ’
t e s t . lua : 4 : in f u n c t i o n ’ bug ’
t e s t . lua : 8 : in f u n c t i o n <t e s t . lua :6>
[C ] : in f u n c t i o n ’ x p c a l l ’
t e s t . lua : 6 : in f u n c t i o n <t e s t . lua :6>
coroutines.lua:6,8
coroutine.wrap ( function () xpcall ( function ()
bug ()
Approach #3: pros and cons
Pros
Resembles synchronous code,
Approach #3: pros and cons
Pros
Resembles synchronous code,
Provide abstraction of ïŹ‚ow control,
Approach #3: pros and cons
Pros
Resembles synchronous code,
Provide abstraction of ïŹ‚ow control,
Keeps stack untouched!
Approach #3: pros and cons
Pros
Resembles synchronous code,
Provide abstraction of ïŹ‚ow control,
Keeps stack untouched!
Approach #3: pros and cons
Pros
Resembles synchronous code,
Provide abstraction of ïŹ‚ow control,
Keeps stack untouched!
Cons
Some boiler plate still needed for each ïŹ‚ow
Approach #3: pros and cons
Pros
Resembles synchronous code,
Provide abstraction of ïŹ‚ow control,
Keeps stack untouched!
Cons
Some boiler plate still needed for each ïŹ‚ow
Summary
(a) Callbacks
(b) Promises
(c) Coroutines
And the winner is!
Coroutine
Question and Answers
Bibliograpy I
B. Fisher.
Indiana jones and the temple of doom.
https://www.ïŹ‚ickr.com/photos/7thstreettheatre/16587334520, 2015.
Cropped out ticket and release details. See licence:
https://creativecommons.org/licenses/by/2.0/ (Attribution 2.0 Generic (CC
BY 2.0)).
Oliver Kowalke.
http://www.boost.org/doc/libs/1 61 0/libs/coroutine/doc/html/coroutine/intro.ht
Distributed under the Boost Software License, Version 1.0. (See
accompanying ïŹle LICENSE 1 0.txt or copy at
http://www.boost.org/LICENSE 1 0.txt).

More Related Content

PDF
ĐĐœŃ‚ĐŸĐœ БоĐșĐžĐœĐ”Đ”ĐČ, Reflection in C++Next
PDF
Clang tidy
PDF
2018 cosup-delete unused python code safely - english
PDF
C++20 the small things - Timur Doumler
PPTX
Evgeniy Muralev, Mark Vince, Working with the compiler, not against it
PDF
ĐĐœŃ‚ĐŸĐœ БоĐșĐžĐœĐ”Đ”ĐČ, Writing good std::future&lt; C++ >
PPTX
Let's talks about string operations in C++17
PPT
Whats new in_csharp4
ĐĐœŃ‚ĐŸĐœ БоĐșĐžĐœĐ”Đ”ĐČ, Reflection in C++Next
Clang tidy
2018 cosup-delete unused python code safely - english
C++20 the small things - Timur Doumler
Evgeniy Muralev, Mark Vince, Working with the compiler, not against it
ĐĐœŃ‚ĐŸĐœ БоĐșĐžĐœĐ”Đ”ĐČ, Writing good std::future&lt; C++ >
Let's talks about string operations in C++17
Whats new in_csharp4

What's hot (20)

PPT
The bytecode hocus pocus - JavaOne 2016
PPT
The bytecode mumbo-jumbo
PPT
C Sharp Jn (3)
PDF
clang-intro
DOC
Network lab manual
PPT
Loops
 
DOCX
Network lap pgms 7th semester
PDF
АлДĐșŃĐ°ĐœĐŽŃ€ Đ“Ń€Đ°ĐœĐžĐœ, Đ€ŃƒĐœĐșŃ†ĐžĐŸĐœĐ°Đ»ŃŒĐœĐ°Ń 'Đ–ĐžĐ·ĐœŃŒ': ĐżĐ°Ń€Đ°Đ»Đ»Đ”Đ»ŃŒĐœŃ‹Đ” ĐșĐ»Đ”Ń‚ĐŸŃ‡ĐœŃ‹Đ” аĐČŃ‚ĐŸĐŒĐ°Ń‚Ń‹ Đž Đș...
PPT
Unit 5
 
PDF
[FT-11][suhorng] “Poor Man's” Undergraduate Compilers
PPTX
Php Extensions for Dummies
PDF
CODEsign 2015
PPTX
Hacking Go Compiler Internals / GoCon 2014 Autumn
PPTX
C++ idioms.pptx
PDF
Empty Base Class Optimisation, [[no_unique_address]] and other C++20 Attributes
PDF
One definition rule - Ń‡Ń‚ĐŸ ŃŃ‚ĐŸ таĐșĐŸĐ”, Đž ĐșаĐș с ŃŃ‚ĐžĐŒ Đ¶ĐžŃ‚ŃŒ
PPTX
Understand more about C
PDF
Tiramisu抂芁
PDF
Code GPU with CUDA - Applying optimization techniques
PPT
C++ programming
The bytecode hocus pocus - JavaOne 2016
The bytecode mumbo-jumbo
C Sharp Jn (3)
clang-intro
Network lab manual
Loops
 
Network lap pgms 7th semester
АлДĐșŃĐ°ĐœĐŽŃ€ Đ“Ń€Đ°ĐœĐžĐœ, Đ€ŃƒĐœĐșŃ†ĐžĐŸĐœĐ°Đ»ŃŒĐœĐ°Ń 'Đ–ĐžĐ·ĐœŃŒ': ĐżĐ°Ń€Đ°Đ»Đ»Đ”Đ»ŃŒĐœŃ‹Đ” ĐșĐ»Đ”Ń‚ĐŸŃ‡ĐœŃ‹Đ” аĐČŃ‚ĐŸĐŒĐ°Ń‚Ń‹ Đž Đș...
Unit 5
 
[FT-11][suhorng] “Poor Man's” Undergraduate Compilers
Php Extensions for Dummies
CODEsign 2015
Hacking Go Compiler Internals / GoCon 2014 Autumn
C++ idioms.pptx
Empty Base Class Optimisation, [[no_unique_address]] and other C++20 Attributes
One definition rule - Ń‡Ń‚ĐŸ ŃŃ‚ĐŸ таĐșĐŸĐ”, Đž ĐșаĐș с ŃŃ‚ĐžĐŒ Đ¶ĐžŃ‚ŃŒ
Understand more about C
Tiramisu抂芁
Code GPU with CUDA - Applying optimization techniques
C++ programming
Ad

Similar to Kamil witecki asynchronous, yet readable, code (20)

PPTX
golang_getting_started.pptx
PPTX
C Programming Homework Help
PPTX
C programming language tutorial
PDF
Subtle Asynchrony by Jeff Hammond
PDF
Introduction to Compiler Development
PDF
Introduction to source{d} Engine and source{d} Lookout
PDF
Go 1.10 Release Party - PDX Go
PPTX
C Programming Language Tutorial for beginners - JavaTpoint
PDF
Building resilient services in go
PDF
A CTF Hackers Toolbox
PDF
Rooted 2010 ppp
DOCX
COMM 166 Final Research Proposal GuidelinesThe proposal should.docx
DOCX
COMM 166 Final Research Proposal GuidelinesThe proposal should.docx
DOCX
COMM 166 Final Research Proposal GuidelinesThe proposal should.docx
PDF
C Programming Interview Questions
PDF
7 functions
PPTX
Workshop 1: Good practices in JavaScript
PDF
Go Says WAT?
PDF
Being functional in PHP (PHPDay Italy 2016)
PDF
Writing Macros
golang_getting_started.pptx
C Programming Homework Help
C programming language tutorial
Subtle Asynchrony by Jeff Hammond
Introduction to Compiler Development
Introduction to source{d} Engine and source{d} Lookout
Go 1.10 Release Party - PDX Go
C Programming Language Tutorial for beginners - JavaTpoint
Building resilient services in go
A CTF Hackers Toolbox
Rooted 2010 ppp
COMM 166 Final Research Proposal GuidelinesThe proposal should.docx
COMM 166 Final Research Proposal GuidelinesThe proposal should.docx
COMM 166 Final Research Proposal GuidelinesThe proposal should.docx
C Programming Interview Questions
7 functions
Workshop 1: Good practices in JavaScript
Go Says WAT?
Being functional in PHP (PHPDay Italy 2016)
Writing Macros
Ad

Recently uploaded (20)

PPTX
ManageIQ - Sprint 268 Review - Slide Deck
PDF
Navsoft: AI-Powered Business Solutions & Custom Software Development
PDF
Flood Susceptibility Mapping Using Image-Based 2D-CNN Deep Learnin. Overview ...
PPT
Introduction Database Management System for Course Database
PDF
Digital Strategies for Manufacturing Companies
PDF
Wondershare Filmora 15 Crack With Activation Key [2025
PDF
Nekopoi APK 2025 free lastest update
PDF
2025 Textile ERP Trends: SAP, Odoo & Oracle
PDF
Claude Code: Everyone is a 10x Developer - A Comprehensive AI-Powered CLI Tool
PDF
How to Migrate SBCGlobal Email to Yahoo Easily
PDF
Addressing The Cult of Project Management Tools-Why Disconnected Work is Hold...
PPTX
Agentic AI Use Case- Contract Lifecycle Management (CLM).pptx
PDF
Upgrade and Innovation Strategies for SAP ERP Customers
PDF
System and Network Administration Chapter 2
PPTX
Lecture 3: Operating Systems Introduction to Computer Hardware Systems
 
PPTX
L1 - Introduction to python Backend.pptx
PPTX
Online Work Permit System for Fast Permit Processing
PPTX
CHAPTER 12 - CYBER SECURITY AND FUTURE SKILLS (1) (1).pptx
PDF
How to Choose the Right IT Partner for Your Business in Malaysia
PDF
Understanding Forklifts - TECH EHS Solution
ManageIQ - Sprint 268 Review - Slide Deck
Navsoft: AI-Powered Business Solutions & Custom Software Development
Flood Susceptibility Mapping Using Image-Based 2D-CNN Deep Learnin. Overview ...
Introduction Database Management System for Course Database
Digital Strategies for Manufacturing Companies
Wondershare Filmora 15 Crack With Activation Key [2025
Nekopoi APK 2025 free lastest update
2025 Textile ERP Trends: SAP, Odoo & Oracle
Claude Code: Everyone is a 10x Developer - A Comprehensive AI-Powered CLI Tool
How to Migrate SBCGlobal Email to Yahoo Easily
Addressing The Cult of Project Management Tools-Why Disconnected Work is Hold...
Agentic AI Use Case- Contract Lifecycle Management (CLM).pptx
Upgrade and Innovation Strategies for SAP ERP Customers
System and Network Administration Chapter 2
Lecture 3: Operating Systems Introduction to Computer Hardware Systems
 
L1 - Introduction to python Backend.pptx
Online Work Permit System for Fast Permit Processing
CHAPTER 12 - CYBER SECURITY AND FUTURE SKILLS (1) (1).pptx
How to Choose the Right IT Partner for Your Business in Malaysia
Understanding Forklifts - TECH EHS Solution

Kamil witecki asynchronous, yet readable, code

  • 1. Asynchronous, yet readable, code Kamil Witecki November 16, 2016
  • 3. Subject of discussion (a) Callbacks (b) Promises
  • 4. Subject of discussion (a) Callbacks (b) Promises (c) Coroutines
  • 5. Callbacks Callbacks are simple but lacking. Do not use them.
  • 6. Promises Promises bring more control and structure to our code.
  • 7. Coroutines Coroutines provide best possible results and are our choice.
  • 8. Writing code is easy You write what you have on mind. And understand it. https://en.wikipedia.org/wiki/Scribe#/media/File:Escribano.jpg
  • 10. Example //avoid allocating temporary int void countZeros ( std : : vector <void∗>& a , int ∗ out ) { out = 0; for ( auto i = begin ( a ) ; i != end ( a ) ; ++i ) { i f (!∗ i ) ++out ; } }
  • 11. Example //avoid allocating temporary int void countZeros ( std : : vector <void∗>& a , int ∗ out ) { out = 0; for ( auto i = begin ( a ) ; i != end ( a ) ; ++i ) { i f (!∗ i ) ++out ; } } template<typename Container > auto c o u n t n u l l p t r s ( Container const& cont ) −> std : : s i z e t { return count ( begin ( cont ) , end ( cont ) , n u l l p t r ) ; }
  • 12. Area of interest - asynchronous programming Synchronous Your code Other code Eg. kernel Idle Start operation Complete operation Start operation Complete operation Executes other code Operation results wait for processing Asynchronous Your code Other code Eg. kernel
  • 13. Case study: conversation I We will focus on a example like: e(d(c(b(a(params))))) What in synchronous code gets as simple as: e (d( c (b( a ( params ) ) ) ) ) Or: resultFromA = a ( params ) resultFromB = b( resultFromA ) resultFromC = c ( resultFromB ) resultFromD = d( resultFromC ) resultFromE = e ( resultFromD )
  • 15. Case study: ïŹ‚ow control Next we will be looking into code that reads two ïŹles and compares content: a = io.open ( ’a.txt’) a data = a : read ( ’a’) b = io.open ( ’b.txt’) b data = b : read ( ’a’) compare ( a data , b data )
  • 16. Case study: debugging Last but not least - we will be checking how errors are manifested.
  • 17. Approach #1: callback C++: void r e a d h a n d l e r ( e r r o r c o d e const& ec , s i z e t bytes ) { . . . } read ( . . . , r e a d h a n d l e r ) ; Lua: function r e a d h a n d l e r ( data ) end socket : on ("data" , r e a d h a n d l e r ) JavaScript: function r e a d h a n d l e r ( data ) {} socket . on ("data" , r e a d h a n d l e r ) ;
  • 18. Approach #1: pitfall a ( params , function ( resultFromA , e r r ) i f ( ! e r r ) then return end b( resultFromA , function ( resultFromB , e r r ) i f ( ! e r r ) then return end c ( resultFromB , function ( resultFromC , e r r ) i f ( ! e r r ) then return end d( resultFromC , function ( resultFromD , e r r ) i f ( ! e r r ) then return end e ( resultFromD , function ( resultFromE , e r r ) // . . end) end) end) end) end)
  • 19. Approach #1: phony solution a ( params , HandleResultsOfA ) ; HandleResultsOfA ( resultFromA , e r r ) { i f ( ! e r r ) return ; b( resultFromA , HandleResultsOfB ) ; } HandleResultsOfB ( resultFromB , e r r ) { i f ( ! e r r ) return ; c ( resultFromB , HandleResultsOfC ) ; } HandleResultsOfC ( resultFromC , e r r ) { i f ( ! e r r ) return ; d( resultFromC , HandleResultsOfD ) ; } HandleResultsOfD ( resultFromD , e r r ) { i f ( ! e r r ) return ;
  • 20. Approach #1: how I see it
  • 21. Approach #1: debugging I 1 f s . s t a t ("1.txt" , function () { 2 f s . s t a t ("2.txt" , function () { 3 //obvious error 4 f s . s t a t ( function (){} , function () {}) 5 }) 6 })
  • 22. Approach #1: debugging II Result is ok, error can be easily spotted: >node t e s t . j s f s . j s :783 binding . s t a t ( pathModule . makeLong ( path ) , req ) ; ˆ TypeError : path must be a s t r i n g at TypeError ( n a t i v e ) at Object . f s . s t a t ( f s . j s :783:11) at t e s t . j s : 4 : 8 at FSReqWrap . oncomplete ( f s . j s : 9 5 : 1 5 ) test.js:4 is: f s . s t a t ( function (){} , function () {})
  • 23. Approach #1: say goodbye to your stacktrace I What if we use same function in multiple places? 1 var f s = r e q u i r e ( ’fs’ ) ; 2 function bug ( content , cont ) { 3 f s . w r i t e F i l e ("config.json" , content , 4 function () { f s . s t a t ("config.json" , cont ) ; 5 } ) ; 6 } 7 8 bug ("{}" , "wrong")
  • 24. Approach #1: say goodbye to your stacktrace II Result: >node t e s t . j s throw new TypeError ( ’ c a l l b a c k must be a function ’ ) ; TypeError : c a l l b a c k must be a f u n c t i o n at makeCallback ( f s . j s : 7 8 : 1 1 ) at Object . f s . s t a t ( f s . j s :826:14) at t e s t . j s : 4 : 2 0 at FSReqWrap . oncomplete ( f s . j s : 8 2 : 1 5 ) test.js:4 is: function () { f s . s t a t ("config.json" , cont ) ; While there error is in test.js:8: bug ("{}" , "wrong")
  • 26. Approach #1: pros and cons Pros Easy to use,
  • 27. Approach #1: pros and cons Pros Easy to use, Integrated by default
  • 28. Approach #1: pros and cons Pros Easy to use, Integrated by default
  • 29. Approach #1: pros and cons Pros Easy to use, Integrated by default Cons Degrades to callback hell quickly
  • 30. Approach #1: pros and cons Pros Easy to use, Integrated by default Cons Degrades to callback hell quickly Makes stacktraces unusable
  • 31. Approach #1: pros and cons Pros Easy to use, Integrated by default Cons Degrades to callback hell quickly Makes stacktraces unusable Does not address more complex ïŹ‚ow control scenarios
  • 32. Approach #1: pros and cons Pros Easy to use, Integrated by default Cons Degrades to callback hell quickly Makes stacktraces unusable Does not address more complex ïŹ‚ow control scenarios
  • 33. Approach #1: pros and cons Pros Easy to use, Integrated by default Cons Degrades to callback hell quickly Makes stacktraces unusable Does not address more complex ïŹ‚ow control scenarios
  • 34. Approach #2: Promises Abstract model of asynchronous computation results. Pending .then(fulfillCallback,...) .then(
, rejectCallback) .catch() Resolved Rejected Cancelled OnValue OnError OnCancel OnValue OnError (no actions) (action) (recovery) (no recovery)
  • 35. Approach #2: Case study I Do you remember callback hell? a ( params , function ( resultFromA , e r r ) i f ( ! e r r ) then return end b( resultFromA , function ( resultFromB , e r r ) i f ( ! e r r ) then return end c ( resultFromB , function ( resultFromC , e r r ) i f ( ! e r r ) then return end d( resultFromC , function ( resultFromD , e r r ) i f ( ! e r r ) then return end e ( resultFromD , function ( resultFromE , e r r ) // . . end) end) end) end) end)
  • 36. Approach #2: Case study II Promises let you write it following way: a ( params ) : next ( function ( resultFromA ) return b( resultFromA ) end) : next ( function ( resultFromB ) return c ( resultFromB ) end) : next ( function ( resultFromC ) return d( resultFromC ) end) : next ( function ( resultFromD ) . . . end) .
  • 37. Approach #2: Case study III With a bit of imagination you can read it as: a ( params ) --:next(function(resultFromA) return b( resultFromA ) -- end) --:next(function(resultFromB) return c ( resultFromB ) -- end) --:next(function(resultFromC) return d( resultFromC ) -- end) --:next(function(resultFromD) . . . --end)
  • 38. Approach #2: ïŹ‚ow control Promises are abstract model of computation. Therefore it is possible to build ïŹ‚ow control with them. For example: c(a(paramsOfA), b(paramsOfB)) becomes: l o c a l a = f s . readAsync ("a.txt") l o c a l b = f s . readAsync ("b.txt") d e f e r r e d . a l l ({a , b } ) : next ( function ( r e s u l t s ) return c ( r e s u l t s [ 0 ] , r e s u l t s [ 1 ] ) end )
  • 39. Approach #2: What about callstacks? I 1 var Promise = r e q u i r e ("bluebird" ) ; 2 var f s = r e q u i r e ( ’fs’ ) ; 3 Promise . p r o m i s i f y A l l ( f s ) ; 4 function b( f i l e ) {return function () 5 {return f s . statAsync ( f i l e )}} 6 f s . statAsync ("1.txt") 7 . then (b("2.txt" )) 8 . then (b( undefined ))
  • 40. Approach #2: It’s a trap! 1 var Promise = r e q u i r e ("bluebird" ) ; 2 var f s = r e q u i r e ( ’fs’ ) ; 3 Promise . p r o m i s i f y A l l ( f s ) ; 4 function b( f i l e ) {return function () 5 {return f s . statAsync ( f i l e )}} 6 f s . statAsync ("1.txt") 7 . then (b("2.txt" )) 8 . then (b( undefined ))
  • 41. Approach #2: What about callstacks? II Still not so good: Unhandled r e j e c t i o n TypeError : path must be a s t r i n g at TypeError ( n a t i v e ) at Object . f s . s t a t ( f s . j s : 7 8 3 : 1 1 ) at Object . t r y C a t c h e r ( node modules b l u e b i r d j s r e l e a s e u t i l . j s : 1 6 : 2 3 ) at Object . r e t [ as statAsync ] ( e v a l at <anonymous> ( node modules b l u e b i r d j s r e l e a s e p r o m i s i f y . j s : 1 8 4 : 1 2 ) , <a at t e s t . j s : 5 : 1 3 at t r y C a t c h e r ( node modules b l u e b i r d j s r e l e a s e u t i l . j s : 1 6 : 2 3 ) at Promise . settlePromiseFromHandler ( node modules b l u e b i r d j s r e l e a s e promise . j s : 5 0 9 : 3 1 ) at Promise . s e t t l e P r o m i s e ( node modules b l u e b i r d j s r e l e a s e promise . j s : 5 6 6 : 1 8 ) at Promise . s e t t l e P r o m i s e 0 ( node modules b l u e b i r d j s r e l e a s e promise . j s : 6 1 1 : 1 0 ) at Promise . s e t t l e P r o m i s e s ( node modules b l u e b i r d j s r e l e a s e promise . j s : 6 9 0 : 1 8 ) at Promise . f u l f i l l ( node modules b l u e b i r d j s r e l e a s e promise . j s : 6 3 5 : 1 8 ) at node modules b l u e b i r d j s r e l e a s e nodeback . j s : 4 2 : 2 1 at FSReqWrap . oncomplete ( f s . j s : 9 5 : 1 5 ) test.js:4-5 function b( f i l e ) { return function () { return f s . statAsync ( f i l e )}}
  • 42. Approach #2: pros and cons Pros Code structure and business logic are more coherent,
  • 43. Approach #2: pros and cons Pros Code structure and business logic are more coherent, Provide abstraction of ïŹ‚ow control
  • 44. Approach #2: pros and cons Pros Code structure and business logic are more coherent, Provide abstraction of ïŹ‚ow control
  • 45. Approach #2: pros and cons Pros Code structure and business logic are more coherent, Provide abstraction of ïŹ‚ow control Cons Some boiler plate still needed for each call
  • 46. Approach #2: pros and cons Pros Code structure and business logic are more coherent, Provide abstraction of ïŹ‚ow control Cons Some boiler plate still needed for each call Makes stacktraces unusable
  • 47. Approach #2: pros and cons Pros Code structure and business logic are more coherent, Provide abstraction of ïŹ‚ow control Cons Some boiler plate still needed for each call Makes stacktraces unusable
  • 48. Approach #2: pros and cons Pros Code structure and business logic are more coherent, Provide abstraction of ïŹ‚ow control Cons Some boiler plate still needed for each call Makes stacktraces unusable
  • 49. Approach #3: Coroutines http://www.boost.org/doc/libs/1 60 0/libs/coroutine/doc/html/coroutine/intro.html [2]
  • 50. Approach #3: Case study I We will look, again, at e(d(c(b(a(params))))), now with coroutines! coroutine.wrap ( function () resultFromA = a ( params ) resultFromB = b( resultFromA ) resultFromC = c ( resultFromB ) resultFromD = d( resultFromC ) resultFromE = e ( resultFromD ) end ) ( )
  • 51. Approach #3: ïŹ‚ow control Coroutines allow to build ïŹ‚ow control with them, too. For example: c(a(paramsOfA), b(paramsOfB)) becomes: coroutine.wrap ( function () a , b = c o r o s p l i t ( function () return f s. re ad As yn c ( ’a.txt’) end , function () return f s. re ad As yn c ( ’b.txt’) end) c (a , b) end ) ( )
  • 52. Approach #3: What about callstacks? I 1 local f s = require ’coro-fs’ 2 function bug () 3 f s . s t a t ("2.txt") 4 return f s . s t a t ( function () print "x" end) 5 end 6 coroutine.wrap ( function () xpcall ( function () 7 f s . s t a t ("1.txt") 8 bug () 9 end , 10 function ( e ) print ( debug.traceback ( e ) ) ; return e end) 11 end ) ( )
  • 53. Approach #3: What about callstacks? II > l u v i t . exe c o r o u t i n e s . lua deps / coro−f s . lua : 4 4 : bad argument #1 to ’ f s s t a t ’ ( s t r i n g expected , got f u n c t i o n ) stack traceback : t e s t . lua : 1 0 : in f u n c t i o n <t e s t . lua :10> [C ] : in f u n c t i o n ’ f s s t a t ’ deps / coro−f s . lua : 4 4 : in f u n c t i o n ’ bug ’ t e s t . lua : 4 : in f u n c t i o n ’ bug ’ t e s t . lua : 8 : in f u n c t i o n <t e s t . lua :6> [C ] : in f u n c t i o n ’ x p c a l l ’ t e s t . lua : 6 : in f u n c t i o n <t e s t . lua :6> coroutines.lua:6,8 coroutine.wrap ( function () xpcall ( function () bug ()
  • 54. Approach #3: pros and cons Pros Resembles synchronous code,
  • 55. Approach #3: pros and cons Pros Resembles synchronous code, Provide abstraction of ïŹ‚ow control,
  • 56. Approach #3: pros and cons Pros Resembles synchronous code, Provide abstraction of ïŹ‚ow control, Keeps stack untouched!
  • 57. Approach #3: pros and cons Pros Resembles synchronous code, Provide abstraction of ïŹ‚ow control, Keeps stack untouched!
  • 58. Approach #3: pros and cons Pros Resembles synchronous code, Provide abstraction of ïŹ‚ow control, Keeps stack untouched! Cons Some boiler plate still needed for each ïŹ‚ow
  • 59. Approach #3: pros and cons Pros Resembles synchronous code, Provide abstraction of ïŹ‚ow control, Keeps stack untouched! Cons Some boiler plate still needed for each ïŹ‚ow
  • 61. And the winner is! Coroutine
  • 63. Bibliograpy I B. Fisher. Indiana jones and the temple of doom. https://www.ïŹ‚ickr.com/photos/7thstreettheatre/16587334520, 2015. Cropped out ticket and release details. See licence: https://creativecommons.org/licenses/by/2.0/ (Attribution 2.0 Generic (CC BY 2.0)). Oliver Kowalke. http://www.boost.org/doc/libs/1 61 0/libs/coroutine/doc/html/coroutine/intro.ht Distributed under the Boost Software License, Version 1.0. (See accompanying ïŹle LICENSE 1 0.txt or copy at http://www.boost.org/LICENSE 1 0.txt).