My previous post Debugging the student got me thinking about conversations. Particularly conversations where one person is trying to explain things to the other person. In that post I talked about some ways I see this go south. In this post I want to expand on these ideas with some analogies from programming.

To summarize the previous post, imagine someone trying to explain differential equations to a random person on off the street. Silly, right? A random person off the street won't be able to follow. But I think something analogous happens all of the time. The "teacher" starts babbling about something to the student when the student doesn't have nearly enough background information or context to keep up.

In that post one of the commenters proposed that the issue is teachers assuming too much of their students. My response:

That was a hypothesis of mine too, but it seems to only scratches the surface. If teacher stops to reflect, they'll usually realize that it was silly to try to teach differential equations to someone off the street. It's not that they "actually" think there's a short inferential distance, it's that they didn't ask themself the question of what the inferential distance is in the first place.

Event loops

There is something called an event loop in web browsers. If you're interested, this video explains it and is one of my favorite videos:

What the heck is the event loop anyway? | Philip Roberts | JSConf EU

And if you're not interested, well, I guess I'm going to explain it anyway.

A web browser executes code. But while it's busy executing its code, when you click something, you need it to execute other code for you. "Hey, could you stop what you're doing and check the most recent score of the basketball game please?" You're interrupting!

As an analogy, imagine your accountant sitting at his desk doing taxes. There's a three inch stack of papers on his desk that he's working on. And now you walk in and just have a measly two papers you need him to fill out for you. You interrupt and see if he would mind stopping what he's doing to help you.

Nope! Not gonna happen! That shit on his desk, he's in the zone working his way through it and nothing's gonna get in the way of that!

But if you want, there's another desk in the back with a good 20 inches of papers he also needs to get to. You could put your stuff on bottom of that, and he'll get to it when he's ready. First come first serve. You're last.

The three inch stack on his desk is like the browsers main call stack, and the 20 inch stack in the back is like task queue. (I'm trying to make this accessible but it might be easier if you watch the video, and I'm not sure if this will actually work for non-programmers.)

The way the event loop works, is it continuously polls the task queue, and whenever the main call stack empties, it puts another chunk onto the main call stack. Like the accountant finishing his 3 inches and taking another 3 inches from the 20 inch stack in the back.

Now imagine that you want your accountant to be responsive to clients. Well, you can't put too much stuff on his main call stack. And you also can't put too much stuff on his task queue. This is exactly how it works for web developers. If you do either of those things, the browser won't be responsive to the user. When the user clicks it'll be really laggy.

Ok, so problem solved? Not quite. Now your accountant is responsive to clients, but he isn't getting any work done! His just sitting there all day waiting patiently for clients and not doing anything productive in the downtime.

Here's what I'd propose. Only put like one inch of papers on your main desk at once. That way if a client comes, they'll never have to wait too long for that to clear. From there, that task queue/desk in the back with 20 inches of papers, give your clients the priority. Let them jump to the front of the line. Do away with "first come first serve".

Consider how this would play out. In a normal day, the accountant might have 0.4 inches of paper on his main desk, 17.5 on his background desk, a client comes in, the accountant says to put their stuff at the top of his papers on the background desk, skipping the line, the accountant quickly finishes the 0.4 inches on his current desk (inches wasn't the most realistic analogy...), then his event loop pulls another 1 inch from the background table, gets to work on it, and since the client jumped to the front of the line it's already their turn!

So big picture, the accountant is only doing short bursts of work at a time and is constantly cognizant of the needs of clients, ready to pull in new tasks from them pretty quickly.

Similarly, this is how you want to structure your websites. Don't block the main callstack with stuff that takes a long time. Only do a little at once. That way, the event loop will be constantly looking for input from the user so that it can respond quickly.

With this background information out of the way, I can finally make my point: this is how conversations should work.

Imagine that I'm explaining something to you. I say a couple sentences. Then I pause and check if you have anything to say. No? Then I say a couple more. Followed by another check. My event loop is constantly running, seeing if there are any inputs from you before I proceed. And I only do a little bit at once. Contrast this with something like going on a 90 second long rant where I am caught up with what I am saying and not cognizant of you wanting to interject. A one-way lecture instead of a two-way conversation.

In real life, the way I envision this is not actually pausing every few sentences and saying, "Do you have any comments? No? Ok. I'll continue." In reality it's much more subtle than that. Much more nonverbal. Pausing is still probably a good idea, and sometimes it can also be a good idea to verbally check in with the student, but other times it's more practical to just take cues from their body language and stuff.

But yeah, anyways... when you're the teacher, you want to keep your main call stack short. And you want to constantly have your event loop running. Looking to pull from the task queue so that the student has the chance to say something.

Let's talk about that task queue actually. I don't know about you, but sometimes when I'm talking my mind really starts running and I have like 10 things I want to say that are "waiting in line". And I can't seem to get them out of my mouth fast enough. Using our analogy, it'd be good to put like 2 of them on the main stack and the other 8 in the background in your task queue. But, you also want to give the other person access to the task queue, and you want to let them jump to the front of the line, skipping past the 8 items you have there.

Here's how that'd play out. You've got 2 on the main stack and 8 in the task queue. You say your first thing. Now there's 1 on the main stack. You get a signal from the other person that they have something to say. They add an item to the task queue. It jumps to the front of the line. There are 9 items in the task queue now. You proceed to finish the last item on the main stack. Now the event loop runs and takes that item from them at the top of the task queue, puts it on the call stack, and excutes it, giving the other person a chance to say what they want to say.

Then from there, you don't just execute their item and throw it away. You pay attention to what the result is! Depending on that result, you may want to add a few more items to the task queue and have them jump the line.

Maybe you realize they don't know what a derivative is so you add "teach them what derivatives are" to the top of the task queue, ahead of "teach them more stuff about differential equations". Or better yet, you add "spend some time asking about their math background" instead. It would be similarly foolish to just start blabbing about derivatives for the same reason it's foolish to blab about differential equations in the first place.

Error handling

Another programming analogy that I think fits here is error handling. Consider the following code:

let n = 0;
n += 2;
n += 5;
n -= 3;
n += 1;
fetchAndDisplayCatImages(n);
n -= 4;
fetchAndDisplayCatImages(n);
n += 2;
n -= 3;
console.log(n);

We have a value n. We're adding and subtracting from it. We're using it to get cat images to display to the user. And finally, we're logging the value of n at the end.

But what happens if fetchAndDisplayCatImages fails? Maybe the API changed on us. In practice, what we'd want to do is check to see if there are any errors, and if so, have a pop up box or something tell the user and fail gracefully. We don't want the whole thing to just crash. That's ugly. And perhaps harmful. So we can instead do this:

let n = 0;

n += 2;
n += 5;
n -= 3;
n += 1;

let firstResponse = fetchAndDisplayCatImages(n);

if (firstResponse.error) {
  showErrorPopup("Problem trying to get the first batch of cat images.");
} else {
  n -= 4;
  
  let secondResponse = fetchAndDisplayCatImages(n);

  if (secondResponse.error) {
    showErrorPopup("Problem trying to get the second batch of cat images.");
  } else {
    n += 2;
    n -= 3;
    console.log(n);
  }
}

Make sense. But what about the n += and n -= lines? What if they fail?

Well, they almost certainly won't. Some lines of code we're so confident in that we don't bother checking for errors. Actually, that happens more often than not. Usually we only check for errors when we do something complicated enough where things might actually go wrong.

I think it makes sense to take a similar approach to conversations. Suppose you're tutoring a student in college on differential equations. You've been tutoring him for a while so you don't need to spend time diagnosing where his math skills are like we did in the previous example. So then, you're sitting in the library explaining stuff to him. Things are going smoothly. But then you get to a concept that is particularly tricky. What do you do? Error handling!

You've just made a statement that has some complexity to it, and it's possible that it caused stuff to go wrong. You have to check to see if an error was thrown before moving on. It would be imprudent to just continue rambling along. If an error was thrown, you need to handle it.

In this case, I guess an error being thrown would usually mean the student not understanding what you said. That'd mean you'd have to pause and address their confusion (by trying to debug together).

But not necessarily. Maybe they would just like to paraphrase back to you to make sure they understood. Or maybe they have an interesting comment to make!

I should have talked about exception handling instead of error handling. In programming, usually we're worried about errors, but sometimes there are other exceptional things that happen that we want to be aware of and handle properly. Same with conversations. I think it's probably true that we're most worried about the student "throwing an error", but sometimes the exception that they throw isn't actually an error, and yet it's still exceptional enough that we want to interrupt and handle it.

Social conversations

So far I've mostly been focused on an example of a more educational type of conversation between a student and a teacher. Makes sense that this stuff would apply to that type of conversation. But what about more fun and social types of conversations?

Well, I guess it depends on your idea of fun. Personally I pretty much always prefer my conversations to have error handling and short call stacks, but I've came across people with different preferences. However, I think that those preferences usually only apply to certain contexts, and as a default people prefer error handling and short call stacks. I'll leave you with this Seinfeld clip as an example.

New Comment
2 comments, sorted by Click to highlight new comments since:

I love seeing crossovers between subjects like this, thanks Adamzerner.

People often complain about how rare it is to feel listened to, and I think this is a big part of it. You need to keep your stack small so that you’re shaping and pacing your own lines from their reactions. Listening is a key part of conversations even when you’re the one.... speaking.

I had a mild revelation last year in Improv class where they taught us “error handling” in the form of ”watch whether your partner’s face lights up” whenever you say a line.

It made me realise I was only listening to the words that people were saying in my “error handling” (do they say they understand/are-interested?). But doing this exercise we were ignoring the words entirely (do they look like they’re following/interested?). It turned out to be a lot more accurate and useful because people often wont admit that they’re lost or try to be polite, and it doesn’t slow down conversations as much as asking whether they understand. It’s so simple yet I was blind to it for most of my life.

Glad you liked it! Yeah that makes a lot of sense about those nonverbal cues giving a stronger signal than the verbal ones, while also slowing down conversation less. And that's interesting to hear about how improv improves ones listening skills. I never made that connection before, I always thought of it as more "learning how to be funny"