Hello! You’ve perhaps reached this page because you received a Christmas card that looked something like this:
Merry Christmas!
Your card was handmade and totally unique! It’s part of a series of cards I made this year:
As far as I know this is the first series of Christmas cards that form a stop motion animation, the first to use 3D → 2.5D conversion for cut card, and a shockingly rare example of a geographically accurate London Christmas card!
So now for the story of how I put entirely too much effort into this year’s Christmas cards…
Last Christmas, after years of sending perfectly nice but not very personal commercial cards, I decided to make my own. Seeing as I’d finished running the River Thames this spring it seemed fitting to feature the river somehow. Tower Bridge is almost certainly the most recognisable point on the river, so I set the card there.
However, there was one small problem when I started this project back in August: I can’t draw. No sense of proportion or perspective. Nada.
So instead I turned to the only logical alternative: learn the basics of 3D modelling in Blender.1 After a few attempts at simpler projects I set about modelling my scene. I used OpenStreetMap data to grab all of central London’s buildings, and then modelled a few more prominent buildings manually:
Next, I added a sleigh and some reindeer and worked out how to animate them, the camera, and Tower Bridge:
I had to transform the 3D models into 2D outlines that I could cut into card. To avoid cutting over 500 pieces of card by hand I instead bought a Cricut cutting machine, which can take 2D SVG files and cut them into card. Although there are Blender plugins that can produce SVGs I couldn’t find anything that did exactly what I wanted, so I spent a TGV ride through France writing Python scripts to rasterise my scene’s triangles into 2D, and then relied on Inkscape’s automation to combine these.2
1 base white card layer; 6 layers of bright blue card for most of the City of London’s skyline, including St Paul’s, the Barbican, 22 Bishopsgate, the Walkie Talkie, the Gherkin, and the Tower of London; 3 dark blue layers for Tower Bridge; and 2 pieces of red card for the sleigh, reindeer, and frame.
The Python scripts also generated pixelated “support layers”. Each final card is constructed of 10 coloured layers. I manually assigned which layer each building appears as this prevented buildings “jumping” between layers between different cards. The layers are set up to ensure that all elements are either joined with the frame or, in the case of the sleigh and reindeer, can be aligned with a matching copy on the layer below.
I got through two Pritt sticks gluing all the cards together.
Each card layer is 300gsm; this is thick enough that the Cricut needed two passes to reliably separate the card. In retrospect thinner card would’ve worked better. Cutting the top red layer alone took about 2 minutes; cutting all 3 layers of Tower Bridge took 12.
Cutting these took… a while. I worked in batches and got through several seasons of several TV shows in the background. Assuming nothing went wrong I could typically cut a card in about half an hour, but as I had to cut around 250 A4 sheets I regularly destroyed the cutting mats I was working with, so the card would sometimes slip off and I’d have to start over.
Finally, each card was lined with Rhodia paper and I signed them with Robert Oster’s Heart of Gold ink. Each card is numbered by the original frame from the Blender animation. (I skipped some frames.)
I strongly suspect next year’s cards will be a little simpler… I worked on this on-and-off for much of the autumn, with a final push to actually cut and construct all the cards in late November. Including all the modelling, animation, programming, cutting, gluing, and writing time I easily invested over 150 hours over 4 months. But I had a lot of fun: this was a great excuse to develop some new creative skills.
Shooting the stop motion animation at the top of this page.
It’s been years since I last tried Blender but this was the first time I built anything complex. That said I wasn’t starting from nothing: 3D graphics aren’t exactly new to me.↩︎
For the first time I also relied on LLMs to write a lot of the more boring code for me. A lot of the code is simple: matrix-vector multiplication; depth first searches; filtering geometry that’s too small to cut based on the size of its convex hull. My attitude towards all this code was trust, but verify. I could’ve written all this myself but I used the LLM only to accelerate the process.↩︎
Over the last year and a half I ran the entirety of the River Thames! In total it took 20 runs for a total of over 440km.
Thames Head (west) to Southend-on-Sea (east) (OpenStreetMap). Click on all maps and images in this post to enlarge them!
Let’s get the obvious question out the way first: “why?” And I, errr, don’t have a good reason. It’s not the first time I’ve done a big themed running project, but it’s by far the biggest I’ve ever done.
Second obvious question: “was it a good idea?” Kinda… I really enjoyed running through a lot of the countryside, and for the most part the Thames Path is very easy to run on. It’s also mostly well connected with public transport, which makes the point-to-point nature of the runs manageable. But on the other hand I often spent far more time travelling than running, which made it a much larger time commitment than “just” 20 weekend half marathons.
The best part of this project was seeing the contrast in landscapes and communities across the length of the river. Until now my only familiarity with the Thames was with its murky, curvy path through London or the college boathouses in Oxford.
Near Henley-on-Thames
An interesting historical pattern with the Thames — as with many English cities — is that effluence flows downstream and affluence upstream. A lot of this has to do with the Thames’s role in London’s history: for centuries waste water was literally dumped in the river. Land up river became more desirable. It’s no historical accident that the royal court at Hampton Court Palace was far west of the City of London.
Those historical trends are reflected today, even as sewage practices have improved (a little) and London de-industrialised. House prices are twice as high in Richmond-upon-Thames in south-west London than Bexley, in south-east London. Further out of London, on an Essex-bound train I overheard a group of men lamenting the loss of working men’s clubs, an important third place in their communities, whilst in Oxfordshire I sat near a frightfully posh former Home Secretary concluding with a group of friends that taking the train to a party was a “terrifically smart” decision. (Decisions they made in government weren’t quite so clever.)
Deeper into the country the Thames cuts a path through “green and pleasant” English countryside. Over the course of my 20 runs I developed a newfound appreciation for it. I’ve genuinely come to believe that we’re incredibly fortunate in the UK to be so well connected to so much accessible, open space.
Gear
I ran with a running vest, a 1.5L Osprey water bladder, a handful of snacks (Clif bars in particular), gels, AirPods, iPhone, and Apple Watch Ultra. I experimented with cheaper water bladders but they’re a false economy: after a few runs they’d start to leak and I’d have to replace them.
Pedometer++ on Apple Watch Ultra
The Watch was the MVP of all these: I used Pedometer++ to display my planned route and route taken throughout each run. The app supports both OpenStreetMap and Ordnance Survey tiles; I generally preferred the former as they were clearer on the small display.
For the most part I was following the Thames Path, but I often deviated around it to either explore other countryside or take shortcuts on routes that would otherwise be too long in one go.
Conditions
I ran mostly in winter and spring 2023 and spring 2024. In the winter months the path was often very muddy, whilst in spring there were sections with very overgrown grass (which was joyless with my hayfever). The Thames burst its banks last year, flooding parts of the path. The Environment Agency has pages monitoring current river conditions.
Towards the source of the river the Thames Path is often just a trodden path along the edge of fields. This makes for a very uneven surface: I had to slow down to avoid turning an ankle.
I only ran in the summer once, but even in spring it was often 20º+ and sunny. Most of the route is very exposed: by the end I regularly ran with a baseball cap.
Logistics
I live in London, which made travel to and from each run easy. (Cities in the UK are well connected by rail to London and farless well to one another.) All in I spent about £400 on train tickets, local buses, and (only twice) taxis. I used a railcard to decrease costs but otherwise I generally optimised for time. I’ve no doubt that booking advance singles, split tickets, or cheaper train lines could reduce the cost by at least £100.
At the end of each run I made a tradition of buying a meal deal (or equivalent) and extra snacks: I spent a further £200 on these.
Between Lechlade, Gloucestershire and Teddington, London the Thames is interrupted by dozens of locks. These locks often have extra facilities for boaters, which the Environment Agency lists here. I learned way, way too late (literally at the last lock I ran past) that this often includes drinking water taps that you can use to refill water bottles. A lock keeper recommended running the tap for 30s before using it.
I’ve posted GPX files for all the routes below.
London and Kent
Teddington to Gravesend (OpenStreetMap)
For all the London and Kent routes I took South Western trains, TfL services, or High Speed 1.
The best sections were from Battersea Power Station to Greenwich: you get far more diversity in the built environment on this leg than any other section of the Thames (beyond these points London is mostly just suburbs).
[1/20] Teddington to Barnes Bridge (12.7km): I started by running west with one of the shortest runs. All of the London sections were very flexible as the Thames path is rarely more than a few hundred meters from a TfL connection. Teddington is the final lock on the River Thames and therefore the start of the “tidal Thames”.
[3/20] Tower Bridge to Woolwich (19.5km): I had the option to extend this to Abbey Wood (the end of the Elizabeth line) but didn’t have enough energy on the day.
[4/20] Woolwich to Dartford (21.4km): The Thames Path deviates quite far from the River Thames as it’s interrupted by the Darent from the south.
[5/20] Dartford to Gravesend (20.3km): This was by far the least pleasant section to run: the sewage treatment plants along the river stink, and the marshes aren’t much better. Gravesend definitely wins “worst place name” of anywhere I went.
Essex
Tilbury to Southend-on-Sea (OpenStreetMap)
For all the Essex routes I took c2c trains from West Ham and Fenchurch Street. I chose to cross to running on the north side of the river and run the Thames Estuary Path instead of the Thames Path as it was far better connected to London.
[6/20] Tilbury to Stanford-le-Hope (17km): I ran fairly far inland from the river (the land immediately next to the river was marshy). I wouldn’t recommend this path in winter.
[7/20] Stanford-le-Hope to Benfleet (19.7km): This section was again quite muddy when I ran it in early spring 2023. Benfleet Station was my starting connection for the next 2 runs.
[8/20] Canvey Island (23.6km): I ran a lap of Canvey Island because I’m followed by a group of pedants on Strava who would’ve called me out if I skipped it.
[9/20] Benfleet to Southend-on-Sea (12km): I concluded I’d reached the end of the Thames when I reached a London Stone at Chalkwell, which marks the end of the Port of London’s Authority. However I continued to Southend-on-Sea because I figured if they’re claiming it’s at the seaside rather than the estuary-side that was good enough for me. Finished with fish and chips and ice cream on the beach.
Surrey, Berkshire, and Buckinghamshire
Teddington to Henley-on-Thames (OpenStreetMap)
I took a mixture of trains from South Western trains from Waterloo and GWR services from Paddington. As this whole area is still well within the London commuter belt it had by far the easiest train connections, though the trains were often the busiest.
The Thames at Chertsey
[10/20] Teddington to Chertsey (24.2km): For all the remaining runs I ran west. At Weybridge I had to cross the river via a ferry. Although it felt delightfully old-fashioned to cross the river by ringing a bell to call the ferryman, it was still 2023 so he took Apple Pay.
[11/20] Chertsey to Windsor (22.4km): Ran past Runnymede, shortly before Windsor Castle, which was the site of the signing of the Magna Carta in 1215. I had no expectation of seeing this so it was a nice surprise! Windsor was packed with tourists.
Statue of Queen Elizabeth II at Runnymede, even though I’m fairly confident she wasn’t around in 1215 to watch King John sign the Magna Carta.
[12/20] Windsor to Bourne End (19.5km): Worth noting that around this section the Great Western Main Line and the Elizabeth line run close to the Thames, so there’s a lot of optionality for shorter/longer runs.
[13/20] Bourne End to Henley-on-Thames (20.7km): Lots of pleasant countryside but the path I plotted often took me up over hills and away from the Thames. The river at Henley was the straightest part I think I came across.
Oxfordshire and Berkshire
Henley-on-Thames to Lechlade (OpenStreetMap)
For some of the Oxfordshire runs I took GWR trains directly from Paddington, whereas for others I stayed overnight in Oxford (which is also connected to London via slower Cross Country services from Marylebone).
[14/20] Henley-on-Thames to Pangbourne (30.9km): Around this time I grew a bit more confident with distance but I had the option to cut the run short at Reading. The area around Reading was the last busy part of the Thames Path.
[15/20] Pangbourne to Wallingford (25.1km): I ran a lot of this on The Ridgeway rather than the Thames Path. I originally plotted this route with a plan to take a train back from Wallingford Station … only to discover it was a heritage station with very infrequent services so afterwards I looped back and took a train back to London from nearby Chorley.
The Thames at Wallingford
[16/20] Wallingford to Radley (30.3km): I took a train to Didcot Parkway and a bus to Wallingford for the start of this one. The Thames Path crosses the river at Benson Lock but at the time the footbridge was closed; a ferry operated across the river instead. I suffered my worst hay fever reaction ever towards the end of this run so my pace dropped completely and I walked the last few kilometers back to Radley, where I then took a train to Oxford and another back to London.
Oxford college boathouses
[17/20] Radley to Appleton (31.4km): This section loops through Oxford, so aside from colleges’ dreaming spires you also see Port Meadow, The Trout Inn (which features prominently in Philip Pullman’s The Book of Dust), and the ruins of Godstow Abbey (which features prominently in Mamma Mia: Here We Go Again). I’d argue these are the last tourist attractions on the run: the remainder is all through countryside and very small towns. I had virtually no service for the second half of the run which made navigating back to Oxford a bit of a challenge; I eventually walked to the A420 and got a local bus back.
[18/20] Bablock Hythe to Lechlade (33.1km): The Thames Path switches to the opposite side of the river between Bablock Hythe and Appleton. I believe the pub at Bablock Hythe operates a ferry service, but at the time I was running it was closed. I therefore took a taxi from Oxford to start this run. St John’s Lock is the final (or first!) lock on the river, about a kilometer downstream from Lechlade. At Lechlade I took a local bus to Swindon and trains back from there.
Wiltshire and Gloucestershire
Lechlade to Thames Head (OpenStreetMap)
For all the Wiltshire and Gloucestershire runs I took trains to or via Swindon and then either local buses or taxis to reach towns or villages on the Thames.
[19/20] Lechlade to Cricklade (18.2km): Lechlade marks the end of the “navigable Thames” and aside from a few narrowboats anchored around Lechlade; I only saw one more rowing boat on the rest of the river. This was the quietest section: I only saw a handful of walkers and no other runners.
There’s not much to the Thames beyond Lechlade
[20/20] Cricklade to Thames Head (22km): For the final leg through the Cotswolds I didn’t push the pace at all. The Thames Path hugged the river tightly but my route deviated slightly from it. The only challenge I had was when I encountered a herd of cows that took a little too much interest in me for my liking … the correct solution was not to climb through a barbed wire fence but instead to walk around them calmly, which I unfortunately learned the hard way.
By May the spring at Thames Head had dried up, but I instead found the spring that was the current source of the Thames tucked away in some woodland between the A433 and the A429. I wouldn’t recommend doing what I did, which was to wade through the Thames (it was only a few centimeters deep here!), cut myself on a whole bunch of brambles, and then get stung by a bunch of stinging nettles to find it. But on the other hand there was no chance I was going to run 400km and not find the start.
I continued on to Thames Head, the traditional start of the river and of the Thames Path. There I met a friendly group of walkers and runners, most of whom were about to set off down the path in the opposite direction. I considered getting a pint in at the Thames Head Inn nearby, but instead opted to avoid train delays and cancellations so I caught the train back to London from Kemble.
The spring
The final obvious question: “what’s next?” … A break?! The lesson from this project has been that I don’t mind travel for runs, just so long as the travel doesn’t take significantly more time than the run itself. That said, I’ve definitely got a couple more daft projects in the pipeline…
On a rainy January morning nine years ago I sat in my Year 10 form room. We’d just come back from the Christmas holidays and smartphones were slowly becoming commonplace. Before then most teenagers I knew had some combination of an iPod, a Blackberry, or a “camera phone”. With smartphones came apps.
One of my friends had an iPhone. This was unusual at the time; iPhones had only been available in the UK for a little over 4 years, so by early 2012 hand-me-downs were still uncommon, let alone brand new devices. As we chatted, he showed me an iPhone app for creating custom “Keep Calm and Carry On” posters.
The British government’s propaganda department designed the poster ahead of the Second World War but never used it.1 They destroyed most of the original prints early in the war, but an original was rediscovered and displayed at Barter Books, Alnick in the early noughties. Over the subsequent decade the poster’s popularity grew, spurning everything from mugs to T-shirts to parodies. This was the year of the London Olympics: kitschy British merchandise was in.
Meanwhile, over Christmas I’d been playing with Java and Android development. By this point in my teens I’d been programming for a few years. I was learning by hacking together simple projects for fun: I had no formal training. I’d been looking for an idea for a new Android project, and it struck me that I could probably write a similar Android app. A handful of cheap apps already existed, but none were free.
The original Android version of “Keep Calm” (January 2012)
That first version of “Keep Calm” was nothing more than a simple form that changed the background colour and the text of the poster. I released my app for free on the Android Marketplace — Google Play didn’t exist yet! — knowing that I could probably compete favourably with the features of the existing apps. I hadn’t tested the app on a device as I didn’t have a smartphone yet.
To my great surprise the app was popular. Within a couple of days it had been downloaded over 1,000 times. This was long before the era of teenagers becoming overnight influencers on TikTok with millions of views, so it felt like a big deal. The decision to make a free app was a good one: it quickly grew more popular than its competitors.
Over the next few months the app went from strength to strength. I added alternatives to the poster’s crown and I followed it up with another app that did the same for Kitchener’s WWI posters, though this was not nearly as successful.
There were two big changes to come. In March 2012, a few weeks after I turned 15, I released “Keep Calm Pro”, which added far more features, including changing the background to a custom image. I charged 50p for the app, and advertised it from the free Android app.2 Within a few days I had a modest, steady income. I’d never had a job before, so I was delighted to discover that I could turn my hobby into a side hustle.
The original iOS version of “Keep Calm Creator” (August 2012)
In May 2012 an uncle gave me a hand-me-down iMac. Until then I’d only worked on Windows. The big appeal of getting a Mac was that I could use Xcode to write iOS apps. Over that spring and summer I got up to speed with Objective-C and Cocoa Touch. Towards the end of the summer holidays, just before I started Year 11, I released “Keep Calm Creator” for iOS. It had a similar feature set to the original Android version, and I later added the “pro” features through an in-app purchase, using a similar competitive strategy to the original app.
The rest, so to speak, is history. In the intervening years these apps were downloaded over 13,000,000 times. The app charted in the Top 10 in several countries. It featured in a short article in the Sunday Times.
I maintained the apps for a couple of years, adding new features, and promoting them on social media. I gradually lost interest in the “business” side even whilst the apps were still very popular, and focussed on my studies instead. By the time I started university I’d also lost interest in the UI and technical problems of the apps: I’ve probably spent more time worrying about the line spacing of Keep Calm and Carry On posters than anyone else in the world.
This has remained the status quo for several years. I’ve made no major changes to any of my apps since I was a teenager and they don’t run well on any modern version of iOS.3 As such, I’ve therefore removed all my apps from the App Store.
I’m a little melancholic to close this chapter of my life. I am, however, incredibly grateful for the experience and to the people who supported me along the way.
Curiously, this is far from the end of my adventures in this arena. Whilst I lost interest in the day-to-day problems of “app development”, I discovered a love of GPU programming and compilers. I played a lot with OpenGL ES on iOS in my late teens, and later with Metal. After the release of Swift in 2014 I began to think a lot more about the inner workings of programming languages and their compilers.4 At university I got to explore these far deeper.
The intersection of GPUs and compilers is small, but happily for the last couple of years I’ve worked on the compiler for Metal’s shading language and the driver for Apple Silicon GPUs. A strange series of accidents lead me here, but I can draw a line from that Year 10 form room to my career today.
“Propaganda department” is no exaggeration here: the Ministry of Information’s building inspired George Orwell’s description of the Ministry of Truth in Nineteen Eighty-Four.↩︎
In-app purchases were still uncommon, and in any case I never got my head around the Android API. Meanwhile iOS apps often had separate versions for iPhone and iPad as it wasn’t initially possible to target both with a single app.↩︎
The Android versions haven’t been available for several years for similar reasons.↩︎
My apps used very little Swift, and I’ve never used it professionally.↩︎
A good simple idea well executed. In 1989 Krzysztof Kieślowski directed Dekalog, a series of ten films for each of the Ten Commandments. The characters are residents of the same Warsaw apartment block. Each story only features 2 or 3 characters confronting moral issues themed loosely around each commandment.
In the hands of a weaker director and writer — Krzysztof Piesiewicz co-wrote the series — each commandment may have been taken more literally. My naïve expectation when I first approached the series was that it each episode’s commandment would be obvious. I couldn’t name all ten commandments before watching the series, and the dilemmas of each film often overlapped several commandments. Importantly neither writer imposed their own views onto the characters: the audience is left free to judge the characters, their actions, and their decisions themselves. What might we do in the same situation? Would we ever get into that situation? How would we resolve it?
In some episodes the connection is obvious: I doubt anyone would miss “thou shalt not commit adultery” in Dekalog: Six or “thou shalt not cover thy neighbour’s wife” from Dekalog: Nine.
Artur Barciś appears as a silent, angelic character in most of the episodes, offering glaring warnings to characters as they are on the precipice of breaking a commandment.
However, most are more subtle: in Dekalog: Five a young man is tried for his murder of a taxi driver (“thou shalt not kill”), but much of the story is presented from the perspective of his lawyer, who is increasingly horrified by the death sentence his client receives. This is the only film where Kieślowski takes a political stance and embeds his own view into the story: the state shalt not kill either.
With the exception of Dekalog: Ten (“thou shalt not covet”), a dark comedy, each film’s tone is serious. Ten features two brothers dealing with their father’s death, his stamp collection, and the (slightly absurd) intersection of philatelists and organised crime. It serves as light relief after a series of heavy films.
Most of the moral issues are interpersonal and affect only the characters in the film. Piesiewicz’s influence is more apparent when the moral issues begin to overlap with the law; he was a practicing lawyer at the time and later a member of the Polish senate. Some of his writing is based on cases he experienced. For instance, in Dekalog: Seven a young woman attempts to “steal” her biological daughter, the consequence of an earlier affair with a teacher, from her parents, who have adopted her as their own. The “ownership” of her daughter is ambiguous, but the law is both crystalline and insufficient to resolve the situation. Piesiewicz worked on a similar case through his legal practice.
Kieślowski repeated the idea of a series themed around united values with the Three Colours trilogy. The films are based on the French revolutionary values of liberty, equality, and fraternity; their titles take are named for the French tricolore. Three Colours is a better series, and refines Dekalog’s ideas — there’s plenty of repetition of themes, actors, and music between the two. Three Colours: Red, the conclusion of the trilogy, is Kieślowski’s best work.
Dekalog marked the beginning of Kieślowski’s international success — he and his work had been perceived as too distinctly Polish and insular — and Three Colours benefitted from it as a growing crowd of actors wanted to work with him.
I’m surprised there haven’t been later attempts to theme a series in Kieślowski’s fashion, especially given that he took the same thematic approach twice. The Commandments’ themes of murder, theft, and adultery lend themselves easily to drama. When the US celebrates it’s 250th birthday in 5 years time another series could follow Three Colours and examine how the constitutional amendments of the Bill of Rights affect the lives of Americans today. I suspect an appetite for Easter eggs in a more modern version would overlap the characters and plots of each film more: many of Dekalog’s characters appear in 2 of the films, but usually the appearance is unspoken in the second.
However, Kieślowski’s vision has stood the test of time. The series is not overtly religious: Dekalog: One prominently features a church and explicitly deals with faith and belief, but this is an exception rather than the rule. Its success lies in the universality of its themes and the stories could easily work in just about any setting at any time. Indeed, several of the films have been remade for other markets. That said, they do not need to be: the original Polish versions hold up, with excellent acting, scores, writing, and cinematography.
Although I graduated two years ago, I’d previously never made my bachelor’s or master’s theses public, although the code has always been available. I’ve not touched either project since, but the theses both provide missing context.
MicroJIT: A JIT compiler for the BBC micro:bit (2018; thesis; code). The micro:bit features a low-powered Cortex M0 processor. At the time the primary programming model for the micro:bit was to transfer a binary over USB and reboot the device. My approach instead allowed new programs, encoded in a stack machine-based bytecode format, to be transferred over serial and JIT-compiled to ARM assembly on device.
Stannel and Statick: A parallel embedded processor and a concurrent concatenative programming language (2019; thesis; code). Stannel was a low-powered processor that I design to run on Lattice Semiconductor’s FPGAs, modelled loosely on the Transputers of the 1980s. It was complemented by a custom assembly language and assembler.
Statick, a concatenative language with dependent, affine types, was arguably the more innovative part of the project. It’s concurrency primitives were based on CSP, but used the type system to restrict and prove operations on them. For instance, a channel could be restricted at compile time to “must use N times,” and the compiler would then statically prove it’s used received and sent on N times before the program terminates (the compiler itself doesn’t prove the program won’t deadlock, but eliminates the need to manage the memory associated with the channel).
The thesis won the “Microsoft Prize for best Computer Science Project” the year I graduated.
Thanks to some tight editing to get them under the 10,000 word limit, both theses came to exactly 9,989 words.
With two years since removed, I’m able to reflect on these projects a little more critically. MicroJIT wasn’t innovative as a JIT, and beyond function inlining, bounds check elimination, tail call optimisation, and register allocation it didn’t do much beyond basic assembly (although packing all that onto the micro:bit was a challenge). However, it built a solid grounding in ARM assembly and exposed me to a little more compiler implementation than we’d done as part of our courses.
I’m more proud of Statick (the programming language) than Stannel (the processor). Statick is a fun blend of ideas from a whole host of programming languages (Occam, Haskell, Rust, Forth, Cat, Kitten). Nobody should be writing large programs in it, but it serves as a pleasant proof that it’s possible to build a (quirky) programming language with these ideas assembled into it.
Stannel was my first foray into an intermediate-sized project in Verilog. There’s a lot that I’d do differently now, and would’ve done differently given a bit more time (make it register based, not stack based, fix the memory controller, deepen the pipeline). Regardless, working on Statick and Stannel was a pretty good set up for hacking on compilers for large, parallel architectures (which just so happens to be my day job now).
Most of my peers’ projects tended to be more theoretical, so I was glad I had the chance to marry a little bit of theory and practice (mostly thanks to Alex Rogers, my supervisor).
I’d argue combinatorial projects (like my master’s) are a good approach for most CS students. There’s a tendency at many universities for bachelor’s theses to take the form of “I implemented algorithm X in programming language Y and found Z”, but often X is just from one of their supervisor’s papers, Y is whatever the learned the previous year, and Z isn’t too surprising.1 Turning X into a set forcibly exposes students to a wider set of ideas, and may ensure they’re building something genuinely new. By going off the beaten track they’ll learn a little more too. It’d reduce the duplication amongst submitted theses and better mirror the reality of modern research.
Sadly, Y is usually Java. My own bachelor’s thesis fits this box too.↩︎
For the last year international travel has been all but impossible. Travel anywhere, for that matter: I last left London 9 months ago. I’ve missed exploring. Adventure. I haven’t been to the EU since the UK left last year, but the pandemic couldn’t stop me visiting the EU…
I start the day early. The streets in St John’s Wood are empty — it’s a bank holiday in the UK — and Regent’s Park is too. Here I notice the first problem of the day. Although the sky is grey and unthreatening, the wind is my concern. It’s stripping the trees of their blossom. Pollen is soon in my face and catching on my clothes. I took an antihistamine before I set off; I hope it’ll be enough to see me through.
I reach the Latvian Embassy first and immediately deviate from the route I planned (it would’ve been number 3). The idea and the route for this run emerged months ago. I put it off: I knew that jogging to every EU embassy in London would be close to a half marathon. 27 stops, with navigation between them, was going to take its toll too.
From Latvia I make quick progress: Croatia, Poland, and Sweden are all in north Marylebone. I also stop at Switzerland, because even though it’s not a member state, I still miss it.
Mayfair and Marylebone are built on a grid around squares created by wealthy landowners in the Georgian era. Navigation is easy and it takes me no effort to find Italy in Grovesnor Square. I often jog around this corner of the West End. Malta and Cyprus aren’t far. I jog around St James’s Park to Slovenia.
Lithuania is on Vauxhaul Bridge Road. Not counting my warm-up jog I’ve already covered 10km but I’ve not even covered half the embassies. The road is the busiest yet and the pollution is getting to me.
Ireland is round the back of Buckingham Palace. I hit my stride as a few streets in Belgravia get me to Ireland, Belgium, Romania, Luxembourg, Portugal, Austria, Germany, Spain, Norway (bonus), and Hungary.
In Belgravia a grammar emerges. Each EU embassy flies the EU’s flag and the country’s own flag too (except for Ireland with flag poles but no flags today). The embassies are deceptively large: I discover entrances around street corner that reveal the site must occupy more houses than the front entrance alone. If cars are parked out front, they’re uniformly black and German. Some embassies — or ambassadors themselves, perhaps — opt for short personalised number plates. It’s a nice touch.
Denmark is my favourite. The building, which also houses the Icelandic embassy, starkly contrasts with just about everything else on Sloane Street. Almost all other Belgravia embassies are white houses with pillared porches. Its size surprises me: Denmark has a population of less than 6 million. Other larger countries have much smaller embassies.
I jog past Harrods. Influencers pose for identikit photos all along the street. I’m guilty too, I think to myself: I’ve been taking poorly framed selfies in front of flags all morning.
By the time I reach France I’m flagging. I keep my eyes peeled for a Pret, or anywhere that could serve up a snack. To my slight surprise the bank holiday has kept them closed. I catch my reflection in a shop window: my posture is poor.
I run out of podcasts to listen to; my mind wonders. Many of the embassies are closed, either due to the bank holiday or London’s lockdown measures. Some hadn’t opened in months, according to signs outside. As I document my journey, CCTV cameras outside the embassies do too. Who is watching this? Hidden deep in the embassy are there security officers? Spies?
I jog north through Kensington to Estonia, Bulgaria, and the Netherlands. A Dutch guard notices me, but he’s disinterested. I navigate to Greece through Holland Park using my phone and the printed maps I have with me. The embassy is at the top of the hill. I’m not happy, but I am forgiving: I’m close to the end now.
Surprisingly, it’s not until the Czech Republic that anyone asks me what I’m up to. I explain to the guard, he’s bemused. He’s wearing a white mask with a Czech crest. He tells me there are more embassies in Notting Hill. I know, I tell him. I know.
I finish at Slovakia. For obvious-in-retrospect reasons it shares a building with the Czech Republic.
I’m exhausted. I still have 5km to jog home but I stop twice to grab snacks. A gingerbread man from the Starbucks at Marble Arch gives me a sugar rush but leaves a strong ginger aftertaste in my throat.
Over the morning I ran just over 30KM, 20 of which were between the embassies. My Apple Watch reports that I’ve completed my move ring 720%. I wonder if I needn’t move for the rest of the week.
The morning made for a curious and tiring adventure. This wasn’t really an exploration of Europe at all, just west London. I jogged down streets I’ve never come across before, and perhaps never will again. At times I knew precisely where I was. At times I was lost. I learned a little but saw a lot. As travel restrictions, perhaps I’ll see much more. Perhaps.
It is a truth universally acknowledged that New Year’s resolutions do not work. Each year as January rolls around we set ourselves noble goals to exercise more, lose weight, eat more healthily, smoke less, or sleep more. Yet 88% of these resolutions are doomed to fail.
As much as our intentions may be good, New Year’s resolutions mostly fail through poor goal setting: all of the above are much to vague for a start. Plenty has already been written in favour of using SMART goals but I think we should approach resolutions differently.
The above study found that about half the participants even expected their resolutions to fail. That’s pretty poor, but falls well within our cultural experience of New Year’s resolutions: often our resolutions are just something we come up with off the cuff at a New Year’s Eve party or around the water cooler in early January.1 We might stick with them for a few days, but beyond that there’s not much hope.
Instead, let’s find goals that are easy to implement, and that if implemented are likely to succeed. Most traditional New Year’s resolutions seek to maximise the effect of their change, without taking into account its probability of succeeding. If we instead seek to maximise the expected outcome of the change, we can look at maximising the probability of success. In loose Bayesian terms we might write:
If we’re looking for easy, small changes then nudge theory can serve us well: nudges are changes that alter behaviour in a predictable way, but must be cheap, easy to implement, and not forbid other choices. Sounds perfect! Most nudge literature is written for “choice architects” designing for other people’s decision making, but we can readily apply many of the techniques to ourselves.
Good defaults are essential to nudging: if we automatically fall down “the right path” then we’re maximising P(success | implementation) because we don’t need to do anything differently once we’ve implemented the change. By making the change easy, we maximise P(implementation).
A classic example from nudge theory finds that moving healthy snacks, such as fruit, to eye level and making unhealthier snacks less accessible increases healthy snack sales.2 If we’d like to be healthier then eating more fruit is a good start. Here we can take advantage of behavioural shifts from the last year: many of us now buy groceries online rather than in store, and most supermarket sites allow you to create a “default basket” for essentials. Adding more fruit to this, and then placing it where you’d usually put snacks, could be an easy way to get started.
Alternatively, we may have the goal of saving more money. Many banking apps now offer a feature that will “round up” transactions to the nearest pound or dollar, placing the remainder in a savings account. The initial set-up effort takes seconds, and the probability of success given implementation is certain. You’ll save a modest amount of money, but it’s certainly better than nothing.
I’ve recently attempted to sleep better. My sleep was often disrupted by a bright street light, so I installed better black-out curtains. This took less than an hour of DIY (easy to implement) and I draw the curtains each night anyway (default behaviour). It’s already paying dividends.
As we all face another stressful, draining year in a global pandemic, I think it’s high time we abandon over-ambitious resolutions: let’s find small, easy nudges that may actually improve our lives.
Regent Street
Regent’s Park
The Mall
Piccadilly Circus
For a long time I’ve had walking around and photographing a desserted central London on Christmas Day on my bucket list. Ordinarily the city would be bustling with tourists, workers, and shoppers every day of the year, but inevitably this year was an exception. Instead whenever I’ve gone for walks or runs around Westminster I’ve been confronted with vast empty spaces.
Pictures of desserted cities around the world became a theme of the pandemic. At its outset I hoped they wouldn’t. However, on Christmas Day I walked around the West End and took the above. There were a few others with a similar idea, and around Oxford Circus and Trafalgar Square there were still plenty of people — although I suspect like me they were locals, not tourists.
A view of the City of London from the north-east at Primrose Hill. With clear skies, temperatures reached the mid-thirties for much of the last few days. Made with Nikon D3400, ISO 100, ƒ/5.6, 1/2500s.
I’m always pleasantly surprised when I come across cheap paper that survives fountain pens: you tend to see the nasty effects of feathering and bleeding. However, Ikea’s Fullfölja notebook line — which cost less than $2 — handle the task well.
I saw only a little bleeding (the paper is only 80gsm) but no feathering. For a such a low cost notebook I can’t complain, although I wouldn’t choose to write in this full time. The cover is reportedly “durable card” although I found it took little effort to scratch it.
Paper has long been one of Sweden’s primary exports, so Ikea’s success here is perhaps inevitable, although this notebook is made in China.
The Fullfölja is available on Ikea’s website (UK; US) or in store in their Marketplace.