際際滷

際際滷Share a Scribd company logo
SIGNAL-ING OUT OF
CALLBACK HELL
whoami /Omer Iqbal @olenhad
Functional Reactive Programming
Compositional Event Systems? ^
WHY?
The world is asynchronous
Programs need to interact with the world
But we have Listeners/Observer/Delegate/Callback
Patterns! Life's good! Go away!
// Yeah, the empire still uses Objective C
@protocol DeathStarDelegate {
- (void)didBlowUp;
}
// In DeathStar
@property (nonatomic, weak) id <DeathStarDelegate> delegate
// When Blowing up
[self.delegate didBlowUp];
// In DarthVader who implements DeathStarDelegate
- (void)didBlowUp {
NSLog(@"Need to hire better stormtroopers");
}
PROBLEMS?
Unpredictable Order
Missing Events
Cleaning up listeners
Accidental
Recursion
MESSY STATE Eww
Multhreading OMG
Chaining dependent operations
"our intellectual powers are rather geared to master static
relations and that our powers to visualize processes
evolving in time are relatively poorly developed"
Dijkstra on GOTO
ENTER FRP/COMPOSITIONAL EVENT
SYSTEMS
Imperative programming describes computations as a series
of actions modifying program state
var numbers = [1,2,3,4,5];
var even = [];
numbers.forEach(function(n) {
if (n % 2 == 0) {
even.push(n);
}
});
console.log(even);
In functional programming we describe what we want rather
than how we want it done
var numbers = [1,2,3,4,5];
var even = numbers.filter(function(n){
return n % 2 == 0;
});
In FP we model computations as transformations of values
Declarative
Pure
Threadsafe
Composable
FRP extends this principle to asynchronous flows
SIGNALS
Representing a stream of values (over time)
e.g Async operations like API calls/UI Input/Timer RETURN
Signals
Sends three kinds of events
Next
Error
Completed
Signals can be subscribed to
[lannisterSignal subscribeNext:^(NSString *name){
NSLog(@"%@ is a true Lannister", name);
}];
[lannisterSignal sendNext:@"Cersei"];
[lannisterSignal sendNext:@"Jamie"];
[lannisterSignal sendCompleted];
[lannisterSignal sendNext:@"Tyrion"]; // Nothing logged here. Sorry Tyrion
Creating Signals
- (RACSignal *)signInSignal
{
return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscri
[self.signInService signInWithUsername:self.txtUsername.text
password:self.txtPassword.text
complete:^(BOOL status, NSError *error)
if (error) {
[subscriber sendError:error];
} else {
[subscriber sendNext:@(status)];
[subscriber sendCompleted];
}
}];
return nil;
I know what you're thinking
COMPOSITION!
Signals like values can be transformed via higher order
functions!
Signal A -> Signal B
map
[lannisterSignal map:^NSNumber *(NSString *name){
return @(name.length);
}];
Signal A -> predicate? -> Signal A
filter
[lannisterSignal filter:^BOOL (NSString *name){
return ![name isEqualToString:@"Tyrion"];
}];
Merge
RACSignal *contenders =
[RACSignal merge:@[lannisters, baratheons, starks, tyrells]];
Signal of Signals
[khaleesiSignal map:^RACSignal *(NSString *name){
return [[Khaleesi sharedInstance] fetchDragons];
}];
flatMap!
flatten: Signal (Signal A) -> Signal A
map: Signal A -> Signal B
psst... Also called bind. Shoutout to all the Haskell folks
Chaining dependent async operations
[[[[client logIn]
then:^{
return [client loadCachedMessages];
}]
flattenMap:^(NSArray *messages) {
return [client fetchMessagesAfterMessage:messages.lastObject];
}]
subscribeError:^(NSError *error) {
[self presentError:error];
} completed:^{
NSLog(@"Fetched all messages.");
}];
PIPELINES!
Declarative! => Clear Ordering
Composable!
No explicit state machine to manage!
Unified interface for Async events
Signal ing out of callback hell
BUT!
Not a silver bullet
Hot Signals vs Cold Signals
GOOD NEWS!
RAC3 uses Signal and SignalProducer types to distinguish
SIMPLE, NOT EASY THANKS RICH HICKEY!
Simple vs Complex
Easy vs Hard
questions? answers : end;

More Related Content

Signal ing out of callback hell

  • 1. SIGNAL-ING OUT OF CALLBACK HELL whoami /Omer Iqbal @olenhad
  • 3. WHY? The world is asynchronous Programs need to interact with the world
  • 4. But we have Listeners/Observer/Delegate/Callback Patterns! Life's good! Go away!
  • 5. // Yeah, the empire still uses Objective C @protocol DeathStarDelegate { - (void)didBlowUp; } // In DeathStar @property (nonatomic, weak) id <DeathStarDelegate> delegate // When Blowing up [self.delegate didBlowUp]; // In DarthVader who implements DeathStarDelegate - (void)didBlowUp { NSLog(@"Need to hire better stormtroopers"); }
  • 6. PROBLEMS? Unpredictable Order Missing Events Cleaning up listeners Accidental Recursion MESSY STATE Eww Multhreading OMG
  • 8. "our intellectual powers are rather geared to master static relations and that our powers to visualize processes evolving in time are relatively poorly developed" Dijkstra on GOTO
  • 10. Imperative programming describes computations as a series of actions modifying program state var numbers = [1,2,3,4,5]; var even = []; numbers.forEach(function(n) { if (n % 2 == 0) { even.push(n); } }); console.log(even);
  • 11. In functional programming we describe what we want rather than how we want it done var numbers = [1,2,3,4,5]; var even = numbers.filter(function(n){ return n % 2 == 0; });
  • 12. In FP we model computations as transformations of values Declarative Pure Threadsafe Composable
  • 13. FRP extends this principle to asynchronous flows
  • 14. SIGNALS Representing a stream of values (over time) e.g Async operations like API calls/UI Input/Timer RETURN Signals Sends three kinds of events Next Error Completed
  • 15. Signals can be subscribed to [lannisterSignal subscribeNext:^(NSString *name){ NSLog(@"%@ is a true Lannister", name); }]; [lannisterSignal sendNext:@"Cersei"]; [lannisterSignal sendNext:@"Jamie"]; [lannisterSignal sendCompleted]; [lannisterSignal sendNext:@"Tyrion"]; // Nothing logged here. Sorry Tyrion
  • 16. Creating Signals - (RACSignal *)signInSignal { return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscri [self.signInService signInWithUsername:self.txtUsername.text password:self.txtPassword.text complete:^(BOOL status, NSError *error) if (error) { [subscriber sendError:error]; } else { [subscriber sendNext:@(status)]; [subscriber sendCompleted]; } }]; return nil;
  • 17. I know what you're thinking
  • 18. COMPOSITION! Signals like values can be transformed via higher order functions!
  • 19. Signal A -> Signal B map [lannisterSignal map:^NSNumber *(NSString *name){ return @(name.length); }];
  • 20. Signal A -> predicate? -> Signal A filter [lannisterSignal filter:^BOOL (NSString *name){ return ![name isEqualToString:@"Tyrion"]; }];
  • 21. Merge RACSignal *contenders = [RACSignal merge:@[lannisters, baratheons, starks, tyrells]];
  • 22. Signal of Signals [khaleesiSignal map:^RACSignal *(NSString *name){ return [[Khaleesi sharedInstance] fetchDragons]; }];
  • 23. flatMap! flatten: Signal (Signal A) -> Signal A map: Signal A -> Signal B psst... Also called bind. Shoutout to all the Haskell folks
  • 24. Chaining dependent async operations [[[[client logIn] then:^{ return [client loadCachedMessages]; }] flattenMap:^(NSArray *messages) { return [client fetchMessagesAfterMessage:messages.lastObject]; }] subscribeError:^(NSError *error) { [self presentError:error]; } completed:^{ NSLog(@"Fetched all messages."); }];
  • 26. Declarative! => Clear Ordering Composable! No explicit state machine to manage! Unified interface for Async events
  • 28. BUT! Not a silver bullet Hot Signals vs Cold Signals
  • 29. GOOD NEWS! RAC3 uses Signal and SignalProducer types to distinguish
  • 30. SIMPLE, NOT EASY THANKS RICH HICKEY! Simple vs Complex Easy vs Hard