Closures and reactive programming Pub Share

Continued from What is reactive programming.

In the first part, we saw what reactive programming is: have a part of your program react to some event, in another "thread". Basically a fancy callback. Please make sure to read What is reactive programming first, since we'll continue that train of thought.

There are languages that help you with the reacting and some that make it harder to write reactive code. The basic problem with doing something later is that things may have changed in the mean time. In the simple reactive example with the ball, let's change the ball after launching the animation in the background (click Run to see it run):

Notice that c has become a blue circle and when the red circle stops moving, the moveItBack() function will in fact move the blue circle instead of the red circle.... what's up with that? We definetly told it to move the red circle, dind't we? But then, in the mean time, c became blue circle... and when it came time to move it back, the blue ball moved!

Opa! This is what happens when you share state/variables between threads: things go wrong! The blue ball moves instead of the red ball. If we had more than two balls, it would be an even bigger disaster! In this case it's just some balls, but it could be bank transactions, carts with orders in them or another of a million things...

Note that I keep referring to threads but, depending on the actual underlying platform, it may be logical threads as opposed to OS threads... or some other form of asynchronous or later execution.

Enter closures

How do we capture the fact that it was the red ball that we wanted to move later? Well, in "regular" programming, we could certainly create an object and pass it to our later selves... ehh how exactly? It's not like Raphael's animation accepts stuff to pass myself later... so how?

Fortunately, functional languages have the means of creating closures! What is a closure you ask? Well, if you read this you are probably not looking for advanced mathematical formulas so I will tell you that it basically is an "invisible" object that captured the environment the function was defined in! That's a mouthful... check it out:

Defining the draw(c) function is required because inside it, c is a different variable than the global c - right? So our moveItBack function now refers to that c and what's more, when it is passed to the animate object, the compiler creates a closure in which it remembers that c was that red ball at that time...

Pause on that for a second, because this is where the trick is. The c needs to be related to the function call that will capture the closure (like an argument is) - otherwise it will be shared across invocations of the same function. The scope where moveItBack was declared is draw where c is local to that call or closure rather than the global one.

Easier to give them proper names, i.e. replace c with ball so you can clearly see what's going on:

var r = Raphael(0, 0, 310, 280);
axis(r,true);

var ball = r.circle(20, 20, 10).attr("fill", "red");

function draw (c) {
  var anim1 = Raphael.animation({cx: 200, cy: 20}, 1000, moveItBack);
  var anim2 = Raphael.animation({cx: 20, cy: 20}, 1000);
  c.animate(anim1);

  function moveItBack () {
    c.animate(anim2);
  }
}

draw(ball)

ball = r.circle(20, 80, 10).attr("fill", "blue");

Here's is the evidence that we can now move two balls at the same time:

Note that we had to modify draw() to use the original coordinates of the ball... since it will be called with many balls placed all over the place.

Closures you now realize that the two references to `moveItBack` are in fact closures: each time `moveItBack` was passed to the animation object, the compiler created a new **closure**, since we can see that each captured the fact that it was referring to a different ball. We're not dropping any balls now, thanks to Javascript...

Eh, voila

And this is the big trick, isn't it: we just transitioned from a traditional thread-based global mind set "the variables on this thread are mine" to closures!

Easy peasy! Not so in languages without closures support. Some support continuations, which do the same. In such languages, libraries likely don't make widespread use of callbacks... or require objects be passed instead of callbacks (example being Java's callbacks).

Other choice would be to accept a state object and pass it to the function - basically poor man's closures.

Another good choice would be to use some kind of actor/messaging system to encapsulate that state... not as trivial.

Real world

In the real world of things other than red balls and blue balls, the context you would capture in a closure could be a connection back to a client waiting for a reply or a cart to drop something into, a reservation waiting for a ticket or much more... now you see the usefulness of this.

On the dark side, if you forget to call the closure, it is lost, together with whatever resources it may have been holding...

Closures rule! If you want the low down, read more about Closure (computer programming).

Or continue reading on this reactive series with Closure chain or reactive flows.


Was this useful?    

By: Razie | 2014-06-19 .. 2016-05-16 | Tags: post , reactive , javascript , raphael , programming


See more in: Cool Scala Subscribe

Viewed 2587 times ( | History | Print ) this page.

You need to log in to post a comment!