vladh's microblog

What is the Most Minimal UK Address Possible?

Postcodes in the UK are pretty specific — a postcode such as “SE1 6AD” will often identify one or a few specific buildings, unlike countries where a postcode represents an entire neighbourhood.

This leads to an interesting question: how short can you get an address and still have Royal Mail deliver post there?

To figure this out, I decided to find the most minimal way to write my home address, send myself a letter using that address, and see what happens. To avoid doxxing myself, I’ve carefully changed the address readers see.

This is how I would normally write my address:

Flat 2
20 Harper Road
SE1 6AD
London

In my building, mail for all flats gets delivered to the same postbox, so we don’t need the flat part.

20 Harper Road
SE1 6AD
London

Writing “London” is also definitely not necessary — the outward code part of my postcode, “SE1”, already says “south-eastern London”, that’s what “SE” stands for.

This leaves us with:

20 Harper Road
SE1 6AD

Can we get more minimal than this? We can — Harper Road is the only road in the “SE1 6AD” postcode, so there is no use writing the road name.

Our final address is:

20
SE1 6AD

We can’t get the address any shorter than this, because there are multiple house numbers in my postcode, and without the house number it would not be clear which house to deliver to. I am sure some postcodes only contain one house number, in which case you could use just the postcode as your address, which would be quite cool. Anyway, this is good enough for me.

I wrote myself a letter, headed to the nearest postbox, and posted it.

Me putting the letter into the postbox
Me putting the letter into the postbox

A couple of days later, I was very happy to find this in my postbox!

The letter I received, on my desk
I got the letter!

User-Friendly Hostnames with Yggdrasil

Yggdrasil allows you to easily set up a private virtual network based on IPv6. Your machines will then receive an IPv6 address such as 201:2af6:fcc4:30e7:b22d:15d6:a55d:10bb. However, that’s not very fun to have to type, and it would be nicer to be able to refer to your machines by their hostnames, e.g. by doing ping apples and ping pears.

I tried to do this in an intelligent way and failed, which led me to resort to setting up a local dnsmasq server to solve the problem. Still, I thought I’d write about my reasoning, since it could lead to a better solution in the future.

Hosts file

The most obvious solution is to stick some entries like this in /etc/hosts:

201:2af6:fcc4:30e7:b22d:15d6:a55d:10bb apples
202:a024:caff:1010:b501:14e2:ee1e:4400 pears

However, I don’t like this solution, because this file needs to be in a system-wide location, which means it’s difficult to version, which in turn means you have to update it separately on each machine. Let’s look for something else.

mDNS

Usually, you might accomplish this using something based on multicast DNS (mDNS), such as Avahi. These solutions send out a multicast packet to all machines on some local network, asking for information about themselves. This means that all machines on the local network are automatically discovered with zero configuration and can be referred to by their hostnames out of the box:

vladh usu ~:main $ avahi-browse -a
+ wlp0s20f3 IPv6 usu [d8:3b:bf:b3:c7:2a]        Workstation          local
+ wlp0s20f3 IPv6 Music Player @ usu[443]        Music Player Daemon  local
+ wlp0s20f3 IPv4 RouterA [00:11:32:ab:55:bf]    Workstation          local
+ wlp0s20f3 IPv4 RouterB [00:11:32:b1:87:4d]    Workstation          local
+ wlp0s20f3 IPv6 RouterB [00:11:32:b1:87:4d]    Workstation          local
+ wlp0s20f3 IPv4 EPSON WF-7710 Series           UNIX Printer         local
+ wlp0s20f3 IPv4 XXXXX___s iPhone               _rdlink._tcp         local

Unfortunately, Yggdrasil doesn’t support multicast networking, so this won’t work. Still, perhaps we can get some hints if we look at how mDNS is integrated into the Linux networking stack.

nsswitch

On glibc-based distros, hostnames will be resolved using a list of strategies listed in /etc/nsswitch.conf. We’re interested in the hosts entry, and here’s what that might look like:

hosts: mdns_minimal [NOTFOUND=return] files dns

This is saying that, first of all, the mdns_minimal plugin should be tried, which is the plugin that calls out to Avahi to make that multicast request. If that doesn’t work, we can try using the files plugin, which just looks the hostname up in /etc/hosts. If our hostname is not in there either, we fall back to the dns plugin, which looks up the nameserver we’re using in /etc/resolv.conf and makes a DNS request.

The ideal solution would probably involve adding some kind of yggdrasil plugin, which asks Yggdrasil for the list of peers we can connect to and attempts to resolve hostnames that way.

Unfortunately, this plugin doesn’t exist (perhaps you want to write it?). Additionally, nsswitch is only supported in glibc-based distros, so musl-based distros such as Alpine Linux would not support this approach at all, just like they don’t support any kind of mDNS.

dnsmasq

None of the things we’ve tried so far ended up working, so let’s just set up the most obvious solution. We could run our DNS requests through a local instance of lightweight DNS server dnsmasq. Then, we can tell dnsmasq to return a specific IP when queried for the address of a certain host.

I use NetworkManager, so I set up dnsmasq with it as described on ArchWiki. Then, I created a dnsmasq.conf file in /etc/NetworkManager/dnsmasq.d with the following contents:

addn-hosts=/home/vladh/.config/hosts

The ~/.config/hosts file contains what you would normally put in /etc/hosts:

201:2af6:fcc4:30e7:b22d:15d6:a55d:10bb apples
202:a024:caff:1010:b501:14e2:ee1e:4400 pears

However, this file is inside my home folder, so it’s very easy to version. Also, running dnsmasq has some other benefits, such as the performance boost gained from having a local caching DNS server. I will also use this file to define custom hosts for other purposes than Yggdrasil, for example to make up for the lack of mDNS support on Alpine Linux.

The downside is that hosts are not automatically detected, so you still have to update a file when you add a new machine.

Overall, I think this solution is good enough. Let me know if you know of a better approach!

Tiny Code Christmas Day 4

Tiny Code Christmas is a fun Christmas-themed coding challenge. I did day 4 in Hare (making it not so tiny).

Code: 04.ha

The Epistemic Implications of AI Assistants

Lately, AI assistants based on large language models, such as OpenAI’s ChatGPT, have caused considerable excitement. The general idea is that you supply a problem, such as “here’s my Javascript code, why doesn’t it work?”, or “write two paragraphs about the political views of Bertrand Russell”, and the assistant will happily supply you with a solution. There’s good reason for excitement — these models are technically impressive, and they can certainly help us accomplish certain tasks more easily.

However, I would like to argue that how we use these models is crucially important. There are specific kinds of problems that such assistants can help us solve, and certain other kinds of problems where they actually cause harm. This harm is of two different kinds. First of all, in certain situations the solutions provided by these models have a high likelihood to be faulty, which can harm our work. Secondly, our reliance on these models in these particular situations can harm our epistemic self-development by incentivising us to not acquire knowledge that would actually be necessary and beneficial. I haven’t seen many people draw this line, which I find worrying. I also think that this perspective tempers some of the more overzealous claims regarding the usefulness of these models, such as “programmers will be replaced by ChatGPT!”.

I will use programming as an example, but my point should be just as clear if you know nothing about programming.

Levels of Complexity

Any particular task can require us to understand things at different levels of conceptual complexity. Let’s consider a very rough and purely illustrative sketch of what the different levels of understanding required when solving a programming problem might look like:

  1. Layer 1 (trivial): looking up how to return multiple values from a Go function.
  2. Layer 2 (nuanced): using algorithms that enable your code to be performant.
  3. Layer 3 (complex): choosing the architecture and dependencies that maximise long-term maintainability of your project.

The very important point here is that the problem can exist on a certain level of complexity, while a certain person’s understanding might extend down to a different level of complexity. For example, let’s say I am familiar with Go (layer 1), but know nothing about performance, time complexity or profiling (layer 2). If I am faced with a problem related to some aspect of Go, that’s not an issue, because the problem and my understanding both exist on layer 1.

However, if I’m dealing with a performance problem, I’m now in trouble, because the problem exists at a lower level (layer 2) than my understanding extends to, so I can’t solve it without somehow expanding my knowledge. Of course, I might solve this problem by lucky coincidence, or by blindly implementing what someone suggests on the internet, but this is really not doing me any service: I have not understood why I chose this solution, and if some future issue arises with it I will be clueless as to what to do, because my knowledge will still not extend to a low enough level, perhaps leading to a compounded and much more dramatic problem.

Encyclopedic and Interpretive Tasks

Obviously, the above example is extremely hand-wavy, but I think we can get an important distinction out of it. Many problems can be split into those that are “encyclopedic” and those that are “interpretive”. In academia, this is sometimes described as a distinction between “bookwork” and “practical work”.

Looking up the population of Scotland, or how to return multiple values from a Go function, or how to use a certain programming library, are all encyclopedic tasks. The information is all already out there — we merely need to look things up and glue our findings together, but there is little original thought required on our part.

On the other hand, interpretive tasks do require some interpretation of the information, some original thought, and often some domain experience. If I’m trying to choose which programming language to use for my 3D videogame engine, there are a lot of considerations I have to take into account — there is no universal answer.

Some might object by saying that ChatGPT does actually perform some kind of interpretation, and does not simply spit out information found in its corpus. I will very quickly describe why I do not believe this to be the case.

First of all, the necessary inability of such models to deal with implicit assumptions is quite a severe limitation. If I ask ChatGPT to help me build a web application, it will inevitably make assumptions as to which programming language I might use, how I might structure my code, whether I might need a database, what kind of database I might need, and so on. The only solution is for us to provide increasingly more detailed input so as to make these interpretive considerations explicit, but the more we do this, the more we’re doing the work instead of having the machine learning model do it, so the model isn’t doing much interpretation.

The second reason is an empirical one. Playing around with these models even briefly makes it clear that their abilities for inference is extremely limited, and that no general capacity for logic has yet emerged from looking things up in a corpus.

Vlad: Anne’s husband’s mother lives in France. Anne lives in the same country as her mother-in-law. Where does Anne live?

ChatGPT: It is not possible to determine where Anne lives based on the information provided. In order to answer this question, additional information would be needed, such as the specific country in which Anne’s mother-in-law lives.

Using AI Assistants

My point here should already be obvious. AI assistants merely aggregate and access a large corpus of information, and so they might be useful for encyclopedic tasks, just as a search engine is. I don’t think there is a problem with using these assistants for the same purposes you would use Google, i.e. as a reference for looking up information that needs no interpretation. However, many tasks are interpretive tasks, and one might be misled into using something like ChatGPT to solve such a task.

There are two possible outcomes when this happens, and both are damaging. Firstly, perhaps the AI assistant has given you a solution that “works”, i.e. it solves your immediate problem. However, you don’t know why this solution works, so if a related problem comes up in the future, you will have an even bigger problem than you started out with. You will have also missed out on a great opportunity for learning, and will now be forced to maintain a mysterious machine-generated artefact. In a sense, it’s a bit like guessing — guessing the right solution doesn’t make you a specialist, because your ability does not extend past the specific instance of the specific problem you guessed the answer to.

The second possibility is that the solution appears to work, but actually doesn’t. This should be no surprise — there is no guarantee that something suggested by a machine learning model will not have numerous problems and pitfalls. You nonetheless deploy the solution into production, and everything quickly goes wrong while you are ill-equipped to fix it.

The Epistemic Implications

We have seen some practical bad outcomes of using AI assistants in the wrong situations, but my bigger point is that there are even worse epistemic difficulties: relying on these models is likely to make us feel that it is less necessary for us to develop our knowledge, or at the very least, the urgency of doing so is much reduced.

If you have a black box that gives you what you think is the right answer every time, or even a lot of the time, what is the point in pushing yourself through the demanding process of learning when you can just rely on the box? Furthermore, you’re liable to be overconfident in your abilities if you feel like you have a magic tool to extricate you from any pickle. Basically, we might think: ”what’s the point in putting in a lot of effort to learn if ChatGPT can just solve the problem for me?”. But there is a point; our objectives should be self-development, knowledge and long-term ability, not short-term hacks, especially when, as we’ve seen, the hacks are often nothing more than faulty short-sighted solutions.

This is akin to cheating on a test — you think you’ve solved the problem, but all you’ve done is cause a big issue for your future self who does not have the knowledge you have just pretended to have.

I find this very harmful for self-development, and the harm is magnified when we consider fields that are more important to us personally than programming, such as communication. I’ll use an example to illustrate this.

Communication

I admit that this post was motivated by the following Hacker News comment:

“I write things a lot of times in not the nicest way. Not mean but very blunt and matter of factly.

I’ve started to use GPTChat for important emails and it’s been a huge help. I can’t wait to have it directly integrated into my email app.”

Let us examine this person’s comment through the two lenses we have been using, the practical and the epistemic.

When it comes to the practical, we should take into account that there are different levels of necessary knowledge when writing an email, just as we saw with the programming example. It is trivial to write an email sending last month’s invoice, but slightly more difficult to articulate our disagreement with an argument by being civil yet firm, and even more difficult to take into account our personal knowledge of the person we are talking to to defuse a difficult situation.

It might be fine to have a program generate a trivial email for us, but it seems uniquely foolish to allow a program to construct the tone we use when talking to our co-workers, because our interpersonal relationships are based on many details and nuances only we know, and this is still true when we have difficulties expressing these nuances. I would also argue that most people would not react positively to finding out that a program had been writing the emails of the person they were communicating with all along.

The epistemic considerations are, to me, where an even bigger problem arises. I can sympathise with the commenter’s lack of self-confidence when it comes to communication — I am aware that communication is difficult, and I have written about this. However, if communication is such a vital skill, improving it should be prioritised, especially when one feels one’s skills are lacking. Using a computer program to communicate does not help in the very important task of improving our communication abilities, and instead just glosses over and exacerbates the issue.

One might say that this is an unfair criticism, because I do not know that this person is not also actively working to improve their communication alongside their usage of ChatGPT, so one might not exclude the other. However, I believe that using ChatGPT in this situations is not only orthogonal, but actively harmful to improving one’s communication, because the end result is that one misses out on important opportunities to learn from interpersonal contact, demanding and effort-laden as these opportunities might be.

Using ChatGPT “for important emails” is therefore liable to distort one’s interpersonal interactions and, if anything, worsen one’s communication skills instead of improving them.

Conclusion

The point I’m trying to make is not specific to programming or communication. I have simply used these two examples to illustrate a bigger point: “solving” problems we struggle with by blindly relying on computer-generated solutions we do not understand harms our process of acquiring knowledge.

Using these AI assistants as a search engine for encyclopedic tasks is not likely to cause us any more harm than using Google does. However, many problems are interpretive, and struggling with any problems of this kind is a good signal that we need to improve our knowledge and skills to better navigate the world around us, be that world professional or personal. Using a computer program as a crutch in situations that require our knowledge and personal expression is unlikely to give us good results in the present, and will certainly harm our ability to develop as people in the future.

Lastly, it should be obvious that if ChatGPT is only able to perform encyclopedic and not interpretive tasks, we’re unlikely to lose our jobs to it anytime soon.

Further Reading

Our Schools Should Teach Communication

Communicating with other people is an activity that permeates almost all aspects of our lives. At the workspace, we have to reason and debate with coworkers and bosses. In family life, we have to seek common ground with loved ones who have different views — maybe we disagree with our parents or grandparents on topics which are important to us, such as religion. At home, we want to be able to enjoy our time with our partners and children without wasting it on perpetual trivial arguments.

At the same time, communicating with others is also a skill that can be developed, and because it’s important in our relationships, it’s also important to our happiness. After all, we have all experienced the consequences of failure to communicate: frustration, endless arguments, even heartbreak.

Despite all this, I don’t recall communication ever even coming up in my education, and I’m pretty sure this is true for most people. This is alarming, and the negative impact this has on society is evident. How many times have you heard an argument end with “I just don’t see how you can think that”, or “why won’t you just be reasonable?”. If you unpack these commonly-heard sentences, you’ll see that they boil down to a complete failure to understand the other person.

I hardly need mention the state of public debate, be it in the UK Parliament, the US Congress, or just on Twitter, where what could be an opportunity to learn from others devolves into shouting matches and partisan football-team-style factionalism. I’m not saying these problems are new or unique to our day and age, but I am saying that we can do better than sowing conflict and squabbling amongst each other.

Even if you agree that change is necessary, you might think that we face an insurmountable problem, namely that communication is too “soft” and nebulous to be able to teach or study. While it’s true that taking a course won’t lead one to deep empathy with co-workers and family members overnight, there are very solid approaches to becoming a better communicator that have been successfully used everywhere from marriages to international conflict zones.

An example of such a strategy is laid out in the book “Nonviolent Communication” by Marshall B. Rosenberg, and the ideas are not at all nebulous or mystical. The fundamental concept is that, while everyone has different priorities in their day-to-day life, we all share a set of common needs, such as the need for a sense of belonging, the need to express our creativity, the need to be heard by others, and the need for a sense of security in our day-to-day lives. The point is not to build some kind of comprehensive taxonomy of human needs, but rather to acknowledge that the exact same kinds of feelings that drive us are present in the people we interact with as well. This leads us to frame what the person across from us is trying to express in terms of feelings we can understand, which makes us much better communicators.

People used to a more confrontational style of argument may find the focus on harmony and empathy counterproductive to healthy argumentation and discarding bad views. This is, however, not the case at all, because, in any event, fully understanding your fellow debater’s argument is a prerequisite to refuting it. In the words of Daniet Dennett, “it is worth reminding yourself that a heroic attempt to find a defensible interpretation of an author, if it comes up empty, can be even more devastating than an angry hatchet job”.

Others might object that curious students and enterprising adults alike hardly have time for the added burden of all this added education — “I’m already busy enough”, cries the CEO! But is there anything more deserving of your time than developing a skill that will enable you to avoid frustration, be better at working with others, and make the most of what you can learn from those around you?

Some people might find it difficult to inspect their own feelings, and one can hardly blame them, considering that many of us, boys in particular, are taught to repress those feelings when growing up, lest we be described as “unmanly”. But the introspection is worth it, because the benefits are not at all abstract or touchy-feely.

In workplace debates, having more empathy for others enables us to find solutions that are more evidence-based, rather than clinging onto our own approaches. In family life, being understanding of others’ needs can help us find common ground with family members, even those who support a different political party or hold ideas we find unpalatable. And at home, instead of letting our time get eaten up by petty debates over household chores or jealousy, being a better communicator helps us become a better partner and a better parent. In general, truly hearing others and learning from them is not only an act of kindness, but importantly, also a massive boon to our own self-development and harmony. This principle extends all the way from our personal lives to our foreign policy.

If we can make some of our relationships more harmonious, we will also have done wonders for increasing our happiness. Indeed, the people with the worst communication skills also have, in my experience, the most turbulent, unhappy and stressful social lives.

Let’s make a change in the right direction, and encourage communication to be taught in our schools, as well as trying to develop this skill ourselves. We don’t need the perfect curriculum — even by just underscoring the issue’s importance and offering a path forward, we will do a great service to mental health and productivity.


Not sure where to start? Here’s some recommended reading:

Do you have a recommendation for what should go here? Contact me!

video.clumsy.computer is live!

As you may know, I create educational programming videos under the name clumsy computer where I show how to program everyday tools such as a regular expression engine from scratch without using any libraries.

So far, the videos have been hosted on YouTube. That’s fine, and virtually every single viewer has discovered the channel there. However, I (and others) have spoken about how it’s important for programmers to make sure their work is available without depending on ethically dubious companies such as Microsoft and Google. I don’t like knowing that the only reason my educational videos can be hosted for free is that the costs are subsidised by advertising revenue.

I’m therefore happy to announce video.clumsy.computer, which is a PeerTube instance hosted by me where all the educational videos I make will also be available from now on. Not only does this mean that all of my work will be hosted under my own terms, but PeerTube also supports ActivityPub, which means that all users of either another PeerTube or Mastodon instance can interact with everything hosted on the website. Confused by all the terms? It basically means this website is compatible with other people’s self-hosted social networks and video websites.

It feels a lot more cosy for clumsy computer to have its own home, and I also look forward to uploading any non-clumsy-computer videos I create in the future.

In line with this change, I’ve also moved the primary home of all of the code from GitHub to a sourcehut repository.

The eagle-eyed among you may notice that, while this is great, I haven’t actually been making many videos lately, since the last video was published more than a year ago. Perhaps you should be looking out for more news in the near future! :)

As I always say at the end of clumsy computer videos, see you soon and have fun programming!

Visit video.clumsy.computer →

Easy nocheckin with git

Sometimes, you want to add some code to test something out, but you definitely want to make sure you don’t git commit it. Of course, you should always check the output of git diff before you make a commit (you do, right?), but if you have a lot of changes things can slip through the cracks.

A solution is to write a comment containing a string such as “nocheckin”:

function do_stuff() {
    printf("hello!!! testing!!!\n"); // nocheckin
    call_important_thing();
    call_other_thing();
}

Then, you need to set git up such that it refuses to make a commit if it detects the “nocheckin” string anywhere in your changed files. Here’s how to do it.

Save this script somewhere — I put it in ~/.bin/validate-nocheckin:

#!/bin/sh -eu

# get the staged files
s_files=$(git diff --name-only --cached)

# if a staged file contains the keyword, fail the commit
for s_file in ${s_files};do
    if grep -q -E 'nocheckin' ${s_file};then
        echo "ERROR: ${s_file} contains 'nocheckin', failing commit"
        exit 1
    fi
done

exit 0

Then, whenever you want this feature, simply symlink that script as the pre-commit hook by running this from the root folder of your git repository:

ln -s ~/.bin/validate-nocheckin .git/hooks/pre-commit

If you then try to commit your code, it won’t work:

vladh ki test:master $ git commit -m 'will it work?'
ERROR: main.c contains 'nocheckin', failing commit

The Desire to Appear Stressed

It is undeniable that we live in a time of considerable economic inequality. As I write this, one of the headlines on the homepage of The Guardian reads: “UK cost of living crisis: More than one in eight UK households fear they have no way of making more cuts”. This necessarily means that some are able to live a very comfortable life just as others struggle to pay the bills and put food on the table.

You might be thinking I am about to embark on a criticism of the lucky few — far from it 1. Those who are able to live comfortably, are, for the most part, simply living the life everyone should be able to live. However, imagine you happen to be a very successful software developer, or perhaps an executive, who never has to worry about the bills, and most likely never will. It is difficult not to come into contact with the poverty of others — perhaps a family member is struggling to keep their head above water, or your neighbour is worried about being able to pay the rent, or perhaps you simply read about the magnitude of poverty in your country in the news.

If you live comfortably, it’s very common to feel some kind of guilt, or at the very least to wonder if this situation is justified. You might come up with some set of reasons justifying why you deserve your success, but these are always nebulous — there is always an element of luck, a bit of support from relatives, or some other such factor. There is, however, a pretty surefire way to ensure nobody will question your merit: to appear stressed, or indeed, even better, to organise your life such that you actually are stressed. Surely this will make it clear to everyone that success has not fallen into your lap.

The more you think about it, the more you realise it is almost perverse not to do so. Would it not be almost obscene to have an incredibly relaxed lifestyle, without a worry in the world, fully enjoying the fruits of your own success, always on vacation, working remotely from the beach, while relatives and friends struggle? Would this not be almost insulting to them?

At the same time, your desire to telegraph the correct signals to others is leading to you actually having a stressful life, not only because you are constantly worried that you actually do not deserve your success and are hence committing some awful injustice, but also because the desire to appear stressed and hard-working causes you to ultimately take all of the happiness and peace of mind that your success could have brought you and put it in the bin. Is it not sad to be one of the lucky few and never enjoy the fruits of your luck, never lead a relaxed and happy life, simply because of the desire to appear deserving?

This is quite a sad state of affairs, and I believe that this kind of mentality is the source of widespread unhappiness and mental health issues among the well-paid. It leads to a kind of bizarre situation where, if you’re not financially struggling, you’re quite likely to be mentally struggling. So what’s the solution?


The very idea that one is “deserving” of their success and that they built their entire life up with their own two hands is nonsensical. This is okay. There are many obvious ways to receive a little help along the way: perhaps your parents paid for your education, or you got some financial help from a friend. It also helps to live in a society where you’re unlikely to be discriminated against based on your race, gender, sexuality or other factors. But there are many other ways in which you are likely to receive support from those around you. I’m a software developer — I never chose to like software, it’s just what I’ve loved doing since I was a kid. I’m very fortunate that my field is very highly prized by the market, i.e. it pays well. However, this can always change with the times, and if my passion had been tailoring and I had worked just as hard, I would be out of luck. 2

Those with neoliberal tendencies might argue: of course my skills are prized by the market, software development is essential to society! This is, unfortunately, only true in the world of imagination, and there is no better example than that of “essential workers” during the early days of the COVID pandemic, when we endlessly praised doctors, nurses, supermarket workers and others, while paying them peanuts. Is their contribution to society less than mine? 3

It doesn’t stop here, though. Even if you were successful despite market conditions, you are still standing on the shoulders of others. You eat food brought to you from all corners of the world, you rely on transportation networks, on healthcare staff, on sanitation workers and countless others.

You might be familiar with the phrase “it takes a village to raise a child”. Well, it takes a village to raise a CEO as well.

If you take all of this into consideration, it becomes obvious how unrealistic it is to live in a fantasy world of individualism, of being solely responsible for our own success, when in reality, there is some kind of collective effort everywhere you look, which should be celebrated.


If the conclusion is that we all rely on the people and society surrounding us, that it’s nonsensical to say that only you are responsible for your own success, how are the successful supposed to frame themselves in relation to the less fortunate?

It should be clear by now that being stressed and unhappy in the name of others is absolutely foolish and only serves to make oneself miserable while not helping others in any way. It is damaging not only on the individual level, but also on the economic and societal level, to have a class of well-paid but depressed people. Stress is not a badge of honour — if anything, peaceful happiness should be.

The quest for merit, and for “deserving” one’s success should be abandoned. Even though systemic change is necessary to address systemic inequality, we would already do a great service to mental health worldwide if the fortunate dropped the pretence of unnecessary stress and self-flagellation, and instead put their commendable concern for others to good use and rang the doorbell of a struggling neighbour with an offer to lend a hand.


  1. There is a separate obvious argument to be made about how the concentration of wealth enables poverty, but my point is that it is not intrinsically reprehensible to be able to live comfortably. ↩︎

  2. For more on this topic, I can recommend “The Tyranny of Merit” by Michael J. Sandel. ↩︎

  3. No :-) ↩︎

Adding a Temperature Sensor to my Flat

I live in London now, and on the 18th and 19th of July this year, the UK saw its highest recorded temperatures ever. The south-east of England was particularly affected. I personally struggle a lot with heat, and knowing I would find temperatures of up to 40°C unbearable, I escaped London to slightly chillier Portsmouth.

However, before I left, I thought it would be really cool to see how the temperature and humidity in the flat change during the heat wave while I’m away. Luckily enough, I realised I had a Raspberry Pi Zero and a BME280 temperature sensor, so I got to work putting them together. You can get the sensor from Adafruit — it’s easy to connect via I2C and it seems to be quite well-supported when it comes to Linux drivers. Here’s what it all looks like.

A Raspberry Pi connected to a temperature
sensor
My Raspberry Pi Zero connected to the BME280

The next stop was to write some code to get the data off of the sensor. I put together something super quick in Go using a driver someone had already written, and this allowed me to read the temperature, humidity, and atmospheric pressure in a particular instant.

package main

import (
	"time"
	"fmt"

	"golang.org/x/exp/io/i2c"

	"github.com/quhar/bme280"
)

func main() {
	d, err := i2c.Open(&i2c.Devfs{Dev: "/dev/i2c-1"}, bme280.I2CAddr)
	if err != nil {
		panic(err)
	}

	b := bme280.New(d)
	err = b.Init()
	temp, pres, hum, err := b.EnvData()
	if err != nil {
		panic(err)
	}

	fmt.Printf("date=%s ", time.Now().Format(time.RFC3339))
	fmt.Printf("temp=%f ", temp)
	fmt.Printf("pres=%f ", pres)
	fmt.Printf("hum=%f\n", hum)
}

I collected this data every second with a crontab, and sent it off to a webserver. The next step was to make a small web page to interactively display the live data. I normally would have built something custom with D3, but I really didn’t want to spend any time on this, so I just used an off-the-shelf plotting library to put something together real quick. Unfortunately, this resulted in a 4.4MB page size, but this page is really only for my own use anyway, so whatever.

Here’s what the result looks like! :)

A graph of the temperature in my
flat
A graph of the temperature in my flat

You can access the live version at met.vladh.net, which has real-time values from my flat, including humidity and atmospheric pressure.

Right away, I noticed some really interesting stuff in the data. First of all, it’s amazing how smoothly and regularly the temperature changed during Monday and Tuesday, when I was away. I guess that, without any human intervention, and in particular without any ventilation, the temperature changes quite gradually.

You probably noticed the sudden drop in temperature on the 20th, which is when I got back home and opened all the windows. At this point it had gotten cooler outside than it was inside, so ventilation really helped decrease the temperature.

Since then, constant shuffling about and opening and closing windows seems to cause constant spikes in temperature and humidity. I guess this makes sense, but it’s kind of cool and unexpected to see the magnitude of these changes.

The heat wave is (thankfully) long over, but it’s going to be fun looking at these graphs in the future!

Spreadsheet Formula Parsing

Lately, I’ve been working on a spreadsheet program. I think spreadsheets are cool and I often need to use them, but the current software could be a lot better. :) You basically have to choose between impossibly overcomplicated Excel or an army of open-source clones that don’t learn from its mistakes.

Anyway, the really fun part about working on spreadsheet software is that you have to implement a programming language for it! I’m referring to the formula language we all know and love: SUM(A1:B3, 150) and all that.

I’ve started work on implementing something not too far from what Excel has. So far, I’ve written the lexer and the parser. Let’s take some sample input:

= CONCAT(
    "hello",
    SUM(
        A2,
        A2:B3,
        AVERAGE(COL(A), ROW(20))
    ) / (1 + 2) * A2:B3:C4
)

The first step is to lex this into lexemes (e.g. SUM). Let’s run the lexer on the above expression.

name lparen literal comma name lparen cellref comma cellref range cellref comma name lparen name lparen name rparen comma name lparen literal rparen rparen rparen div lparen literal plus literal rparen times cellref range cellref range cellref rparen eof

Oof! Now we need to convert each lexeme to a token (e.g. TokenType::name), then parse all of the tokens into an AST (abstract syntax tree) made up of various kinds of expressions. For example, SUM() translates to the lexemes SUM, ( and ), which are of lexical type name, lparen, rparen, which all ends up being translated into an ExprCall, because this is a function call expression. Let’s run the parser.

call[CONCAT]
  literal[str, hello]
  binarithm[*]
    binarithm[/]
      call[SUM]
        cellref[A2]
        binarithm[:]
          cellref[A2]
          cellref[B3]
        call[AVERAGE]
          call[COL]
            name[A]
          call[ROW]
            literal[i64, 20]
      binarithm[+]
        literal[i64, 1]
        literal[i64, 2]
    binarithm[:]
      binarithm[:]
        cellref[A2]
        cellref[B3]
      cellref[C4]

Looks about right! :)

The next step is to actually write the evaluator, which will walk this abstract syntax tree, evaluate all the expressions and return the result of the whole thing. In our above case, it would probably be, like, hello57 or something, depending on what’s in your spreadsheet.

Hi

So far, I’ve only really posted infrequent manicured content on my website so I thought it would be nice to have a place to more regularly share random things as I work on them, even if this means having small silly posts. To avoid things getting lost in the noise, if a microblog post ends up being particularly good, I’ll promote it to a full website post.

People I follow like Drew DeVault and 100 rabbits have monthly “status updates”, but my updates currently aren’t organised enough for something like this.

One person I know who does something similar is Bill Wurtz with his “expert mode”. You’d think nobody would bother to look through an HTML document with a million tiny posts, but I’ve thoroughly enjoyed looking at everthing Bill has done, even the random everyday bits.

I know this is what people normally use social media for, but the last thing I want to do is host everything I write on the website of a corporation that monetises outrage and bickering. There’s the Fediverse, but self-hosting feels nice.

Unlike content for my website or clumsy computer, the stuff on the microblog isn’t well-suited for teaching, and I don’t go out of my way to explain things so beginners can understand them. Honestly, I’ll probably post about things I don’t understand very well.

Overall, I’ll share things that brought me joy and helped me learn, whether related to programming or otherwise. Thanks for coming along on the ride. :)