Signal ing out of callback hell

Post on 09-Jan-2017

265 Views

Category:

Engineering

6 Downloads

Preview:

Click to see full reader

Transcript

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;

top related