Signal ing out of callback hell
-
Upload
omer-iqbal -
Category
Engineering
-
view
264 -
download
6
Transcript of Signal ing out of callback hell
SIGNAL-ING OUT OFCALLBACK 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/CallbackPatterns! 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 OrderMissing EventsCleaning up listenersAccidentalRecursionMESSY STATE EwwMulthreading OMG
Chaining dependent operations
"our intellectual powers are rather geared to master staticrelations and that our powers to visualize processes
evolving in time are relatively poorly developed"
Dijkstra on GOTO
ENTER FRP/COMPOSITIONAL EVENTSYSTEMS
Imperative programming describes computations as a seriesof 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 ratherthan 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
DeclarativePureThreadsafeComposable
FRP extends this principle to asynchronous flows
SIGNALSRepresenting a stream of values (over time)
e.g Async operations like API calls/UI Input/Timer RETURNSignals
Sends three kinds of events
NextErrorCompleted
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> subscriber) {
[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
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;