My first generator

Recently I wrote my first useful generator function!

pexels-photo-1068523.jpeg
Should probably delete this image.

If you don’t know what a generator function is then best to take a look on MDN. However, if you’re like me and know what a generator is but aren’t necessarily thinking in terms of generators then read on …

Many people, when talking about the utility of generators, will say that they’re really useful for coroutines (basically handing execution back and forth between different contexts), and they are – in fact in many ways it’s generator like syntax that make coroutines tractable in a given language. But for those of us that aren’t writing coroutines on a daily basis then what else can we use generators for?

The above tweet by Axel Rauschmayer (a very worthwhile follow on Twitter by the way) got me thinking about point 2: extracting loop functionality and I realised that using a generator would solve a problem I had actually had recently. Imagine you have a function that helps you walk a tree (again, perhaps not your every day task in JS, depending on what you’re working on, but probably more useful that coroutines). Quite often when walking a tree you’ll want to look for a node like this:


const walkTree = (tree, cb) => {
  cb(tree);
  const children = tree.children || [];
  children.forEach(child => walkTree(child, cb));
};

let foundNode;

walkTree(myTree, node => {
  if (!foundNode && node.id === 'important-node') {
    foundNode = node;
  }
});

The problem with this is that, under the hood, walkTree just carries on through all the nodes … now we could bake in to some return condition, say if we return false then stop iterating but if your return values from this walker get used in a different way, when walkTree gets more complex, then this quickly gets fiddly. Instead we can write a generator:


function* walkTree(tree) {
  yield tree;
  const children = tree.children || [];
  for (const child of children) {
    yield* walkTree(child, cb);
  }
};

let foundNode = null;
for (const node of walkTree(tree)) {
  if (node.id === 'important-node') {
    foundNode = node;
    break;
  }
}

Again if you’re not familiar with bits like the yield* syntax, the have a look at MDN. Now, instead of having to loop through everything or return in odd ways from our callback, we can just write JS keywords, we can break or continue in our loop. We can even label our loop, and while labels are almost always a bad idea they can be useful in some cases where efficiency is very important.

This wasn’t intended to be a long post about how generators work but just a small post about where I found my first useful case for a generator outside of academic hobby stuff. Now whether this is all worth the few kbs for regenerator-runtime is perhaps another thing worth considering right now …

Advertisements

The joys of the HTML canvas.

The HTML Canvas is the perfect meeting point of art and maths.  It allows you to draw things in almost any way you can imagine.  It’s basically a Photoshop with no GUI (although you can make one).  You can use vectors and get bitmap data.  And then you can play around with the maths.

Take the example below which is a a visualisation of a super-position of sine waves (specifically of Fourier Series).  It’s enchanting and you can play with it and watch it forever …

If you don’t know about Fourier Series / Transforms then I recommend a quick wiki.  Joseph Fourier basically said that all waves can be seen as the superposition of different sine waves.  The above visualisation represents sine waves as spinning circles at specific rates (if you reduce the “order” to 1 then this will make sense), where a sine wave’s amplitude is correlated to the radius of a circle.  All of the following circles start on the edge of their predecessor at a specific point (the point where the sine wave would be at zero).  By spinning at different speeds (being out of phase) you get a superposition of these waves as the circles add and subtract their own radius from their predecessor.

Now, not only is this (relatively) easy to do if you know the maths, but if you spend a few minutes looking at how it works, it’s extremely powerful.  There are obviously other technologies that allow you to do this.  But you can do this on the web, on codepen.io, with nothing else!

When you have the code setup, like that above, then you can start playing around with it.  Above, it’s quite easy to see that the whole thing can be changed considerably by changing how the radius of the circle is calculated.  Previously the radius was calculated as 1 / (order * Math.PI) * scale. But if you change it up, say to: scale * (((order % 4) + 1)) you get a radii that repeat every 4 iterations:

TL; DR – I played around with the canvas this weekend …