Learning Hack: Meaning vs Representation

During year 0, I was a high school Latin teacher. And, as the saying goes, if I had a nickel for every time I had to defend studying Latin from people who thought it was useless, I could buy a sandwich and maybe some fries. (But that’s like, 200 nickels!)

“Latin’s dead and you’ll never use it!” people would say. True, there are no native speakers of Latin, and the only time I’ve used it professionally I was teaching it, but there’s a huge benefit of translating sentences from one language into another: It forces you to separate meaning from representation.

source: https://xkcd.com/1562/ (license)

If we only study one human language, the sounds we use to represent thoughts and the meaning of those thoughts are very tightly coupled, so we get the impression that meaning and representation highly connected, but there not. We could even argue that (poetry aside), meaning and representation are only accidentally related.

Let’s take integers, for example. 57 is a good integer. In a computer’s memory, it will be represented by some bits, little endian or big endian, or I could write “fifty seven” in English, or I could say it out loud. Not to mention the other human languages, or writing a binary string or a hex string. All these point to the same integer, so we can say they all mean the same thing, but the representations are completely different.

Computer programmers spend a lot of time choosing between different semantically equivalent ways of representing the same idea. Being able to consider meaning and representation separately is a very important skill.

My goal for this post is to put one simple trick in your mental toolbox: You can now explicitly decide whether you are considering the meaning of something, or its representation, or both. Congratulations! Now that you have this trick, what should you do?

I think, first off, you should apply this trick to information hiding. Code that is calling the public methods you write should care about the meaning but not care about the representation. I am writing code that represents a collection of customers with their phone number. The calling code wants to ask a question like “What is Steve’s phone number?” It does not care that you put Steve’s phone number in a Dictionary<Guid, string>, and therefore it should not know. The meaning of the public API you are writing should be able to remain the same while you change the internal representation of your program. What if your database decides to use integers instead of guids as keys? If your client can see the Dictionary<Guid, string> directly, this change might break every piece of code that uses yours. If all the client can see is a method like GetPhoneNumber(string name), the caller does not care if you swap out the internal data structures.

The second place you can use the differences between meaning and representation is in choosing a readable implementation. Let’s look at the following code snippets.

//Part of both snippets:
IEnumerable<Customer> customers = GetCustomers();
private bool MyAwesomePredicate(Customer customer)
       //Decide whether customer is awesome.
//first snippet:
bool found = false;
foreach(Customer customer in customers)
          found = true;
//second snippet:
bool found = customers.Any(MyAwesomePredicate);

//after one snippet or the other runs

They both mean essentially the same thing: look at the collection ‘customers’ and if you find a customer that meets the criteria in ‘MyAwesomePredicate’ then celebrate. Yay!

The difference is that in the first snippet, whoever is reading this code later is caught up in the ‘foreach’, that is, in the fact that you’re iterating a collection, not in the question that you’re trying to answer. The representation is more evident than the meaning. In the second example, the meaning is evident; you could almost read the code aloud: “The value found equals ‘do any customers meet MyAwesomePredicate'”.  (Also, thanks to Eric Lippert; the example is based on an old blog post of his, which I can’t find right now, about LINQ.)

This is a pretty simple example, and its also one specific to C#, but it demonstrates the point well: separating meaning from representation allows you to consider which representation best serves the meaning of the code, which allows you to write better code. 

So the next time you’re writing a method, and you have an extra few minutes, try some synonymous ways of writing the method. And ask yourself, first “are these really synonymous?” And if they are, choose the one where the representation provides the fewest barriers to future programmers understanding the meaning.

Till next week, happy learning!


Old Teacher Trick: Artificial Constraints Beget Creativity

This post is about a trick my dad taught me. He’s not a programmer, but he is the best teacher of writing that I have ever known. The trick is this: He will make strange requirements part of a creative writing assignment. Only use two characters, or make everything take place in the same train station. Or write a villanelle.

At first, these constraints just seem annoying. Why can’t I just write a story? Why are you stifling my creativity? Don’t confine me, bro! But there is a huge benefit to artificial constraints: they make you do something you wouldn’t have without them. They cause you to be creative. 

Continue reading “Old Teacher Trick: Artificial Constraints Beget Creativity”

Different Ways to Take Notes during an Online Class

Online classes are tricky. No one is watching, no one (except you) cares if you do your homework. No one knows you have 63 other browser tabs open, and a phone on your keyboard. How do you focus?

A major part of my ability to focus in online classes comes from good, old-fashioned taking notes. Here’s my rule: If I can’t write down what just happened, I don’t know what just happened, and I need to close the TV Tropes Periodic Table of Storytelling and actually watch the lecture.

But how do I actually take notes? Pen or keyboard? Crazy diagrams, paragraphs, inscrutable bullet points? What am I actually doing?

Short answer: It depends how hard the material is.

Here are the two basic note taking techniques I use.

Continue reading “Different Ways to Take Notes during an Online Class”

Mindset Post: Handling Discouragement

“If I don’t debug this graph search implementation tonight, I will be poor forever.”

I actually had that exact thought, verbatim, one night during year 2. I was up late. I felt like I was stuck; no matter what I did, I kept messing up the homework problem for one of the algorithms classes I was taking.

I was caught in the worst kind of programming vicious cycle; I would make minor changes I didn’t really understand, build, upload to the auto grader, watch in dismay as I either didn’t fix the problem or made it worse. I would repeat the process.

I let myself get stuck. I was more and more discouraged, and more and more frantic. How can this ever work? Does this mean I’m not a real programmer? Does this mean I should just quit?

There were a few things going on that, in retrospect, I should have changed immediately.

First, every “real” programmer, whatever that means, has certainly lost a few hours of his or her life to a stupid bug. It’s part of the job. (It’s not a good thing, of course, but it does come up.)

Second, life is long. The course I was taking was free. I had a job I liked. I was not out of retries yet. I could always try the course again, try the assignment again, sleep on it, whatever. Part of discouragement is thinking that any immediate failure represents complete failure. That is false. You can fail a lot (and probably will) and still do well. That is life.

I hate movie portrayals of hackers. There’s some kid who’s like twelve, and needs a shower and a haircut, who can make the world change by magically typing fast. That’s dumb. People who are good programmers study hard, learn a lot, do some work. It might not feel quite like work, because they often enjoy it so much, but it is not immediate. It might not happen in a classroom, and it might not look like the book studying that we saw in school, but everyone who’s good at something learned it somehow.

When you get discouraged, do not measure yourself against other people. That is inherently discouraging. It’s inherently discouraging because you see your own struggle, but the other person’s success. It’s like you’re measuring your worst day against their best; struggle is usually private, and success is often public.

Basically, when things are not going well, I have a few choices: I can (1) quit forever, or (2) quit for a little while, take a walk, get a good night’s sleep, and try again, or (3), press on. If you really want to do something, default to option 3, use option 2 when you need it, and never use option 1. That’s it.

I knew a guy who fixed a lot of things, like floors and sinks and whatever, and he had a good saying. Whenever a task was taking longer than he wanted, he would just say, “it can’t win” and keep working. He’s right – it’s not like the tasks you’re attempting actively oppose you. There are two outcomes: You succeed, or you quit. Notice that neither of those outcomes lies outside yourself.

So remember, when you’re discouraged, choose option 3, unless you’re really hungry or tired or your brain is full for the day, then choose 2. Don’t choose option 1.

Till next week, happy learning!