Self-Printing JavaScript Literals

Sometimes you need a totally opaque “constant” — a value that isn’t intended to be projected or modified, and whose only purpose is to be completely different from every other value1. For example, Functional uses Functional._ as a placeholder; a comment on John Resig’s blog suggests defining something like Partial.PLACEHOLDER for something similar.

In JavaScript, these are easy to make. Here’s one: {}. And here’s another: {}. Note that these two values are different: the following code2 will print true, then true, then false:

var L1 = {};
var L2 = {};
console.info(L1 == L1);
>>> true
console.info(L2 == L2);
>>> true
console.info(L1 == L2);
>>> false

The problem with these values is that they look the same when you print them. L1 and L2 both print as Object (in Firefox).

I’m going to print a value now:

console.info(isPrime(172942) ? L1 : L2);
>>> Object

Quick, which one did I print? Sure, you can figure it out in this case (assuming my implementation of isPrime isn’t buggy — probably not a safe bet, especially if you’re having to debug this in the first place), but in general this wreaks havoc with debugging.

Here’s an idiom for making opaque values that can be debugged. This has the further benefit that if the value is bound to a variable, you can use this to create a value that evaluates to itself when you type it back into the console (or into your source code). This works in Firebug and Rhino and OpenLaszlo, at least.

var L1 = {toString:function{return "L1"}};
var L2 = {toString:function{return "L2"}};
L1
>>> L1
L2
>>> L2

If you do use opaque constants often, you can use this makeLiteral utility routine to make them:

function makeLiteral(name) {return {toString:function(){return name}}}
var L1 = makeLiteral("L1");
var L2 = makeLiteral("L2");
L1
>>> L1
L2
>>> L2

Some real-world uses might be:

Functional._ = makeLiteral("Functional._");
Partial.PLACEHOLDER = makeLiteral("Partial.PLACEHOLDER");

In fact, you could go further and define a defining-form. I’m just including this for completeness; the version here doesn’t work unless target itself has a toString() method, and would need more work to be made robust.

function defineLiteral(target, name) {
  target[name] = return {toString:function(){return target+"."+name}}
}
defineLiteral(Functional, '_');


1 Basically an enumerated type or a member of an algebraic data type, except that in meta-level programming these values are often compared to any other value, not just values of a specific type.

2 This would work the same way with === instead of ==, but here it’s not necessary.

Posted: February 15th, 2008
Categories: JavaScript, Tips
Tags:
Comments: 5 Comments.

Supply/Demand Springs

Full size (pdf, png).

Update: This is what I call an entry-level metaphor — it’s a rough sketch of the relation between the concepts, not a productive metaphor that can be used to reason about them beyond this. It doesn’t support analytic microeconomic analysis, and it’s not even consistent at the level of the supply chain. (For example, the unit cost needs to include the component cost, whereas the illustration shows these as complementary; this is because the metaphor leaves out profit.) Nonetheless, I find it a helpful starting point before going more analytic.

It popped into my head when I was answering my son’s question about what “supply and demand” meant. (He had run across it in a Newsweek article he’s reading in his history class.) It seemed to work for him, so I decided to write it down here. We’re both so used to talking about images in words that I didn’t realize until I made this that I’d never actually put it on paper!

Posted: February 7th, 2008
Categories: Illustrations, Visualizations
Tags:
Comments: 4 Comments.

Knowledge Per Unit Time

My friends have been asking me how important I consider experience (again in the context of the election), enough to write the answer down.

Experience can mean contact with facts and events; or, the knowledge and skill that this contact causes. One sense measures the past; the other, the present. It’s the fact that one word has both senses that can allow one to describe the same life history as either “thirty years experience”, or one year of experience thirty times.

But even in its second sense, “experience” is a proxy measure for an unknowable: knowledge and skills that will be useful in the future. To the extent that the future resembles the past, it’s a perfect proxy; where they diverge, the correlation drops.

As a hiring manager, if I were to hire someone to do a specific job and they had done that same job before (in the same kind of organization, with the same tools, and the same requirements and constraints), and I only needed it done the same way, I might look no further.

I’ve never hired for such a job, so what I’m usually more interested in is “experience per unit time”: the efficiency with which a candidate converts the first kind of experience (contact with the world) into the second (knowledge and skills). This is because I expect the candidate to encounter new facts and events, and to need to use these encounters to create new knowledge and skills.

Age is a factor here: not because of the merits of youth for its own sake, but because it shows up in the denominator. If the ability to process life into knowledge and skills were all that mattered, then someone who had seen twenty years of experience (in the first sense) would need show at least twice as much experience (in the second sense) as someone who had only seen ten. This isn’t an advantage of youth, unless you’re comparing candidates with equal experience.

In a democracy, selecting a leader is like hiring an employee: specifically, a manager, or a CEO. (Or in some ways like hiring a contractor, because you can get rid of one by letting the contract run out; it’s harder to get rid of a bad employee :-) .) The same criteria — motivation, ability, character, ethics, knowledge, interpersonal skills, management skills, communication skills, ability to process information and make decisions — apply. Experience, and the ability to acquire it, are important parts of the picture.

Posted: February 5th, 2008
Categories: General
Tags:
Comments: 1 Comment.

Two Thoughts on Elections

What follow are some notes from talking about the elections and the presidential primaries with my children, and some metaphors that I found helpful in thinking about the topics. They’re not otherwise related to each other, except that they all came up over the last couple of days.

1. Votes are Agents

The wikipedia article about voting systems, and the Newsweek article When Math Warps Elections describe a number of different systems: in particular, the America plurality system where you casts only one vote (presumably for your favored candidate, unless you’re voting strategically); approval voting, where you vote for all the candidates your find acceptable (again, unless you’re voting strategically); and ranked-choice or instance-runoff voting, where you rank the candidates, and the candidate who was highest on the smallest number of ballots is removed from all of them until only one candidate remains.

It can be hard to compare these systems. The wikipedia lists some criteria, but it’s a few hours time to learn enough about the theory in this area to apply them.

So here’s a less formal way to think about this, using a metaphor that’s more familiar to most of us (including kids) than the language of the economic theories:

You’re building a robot. The job of the robot is to vote for a candidate, on your behalf. Your robot may need to vote several times: the real election may be built out of a number of micro-elections with different sets of candidates. The reason you’re delegating this to a robot instead of doing this yourself is that it’s logistically easier, and faster, to get each voter to build a robot1 once than to get each voter to show up for each micro-election.

One way the voting systems differ is in how much you get to tell your robot; and, therefore, what your robot does in the elections where your first-choice candidate isn’t on the ballot2. In a plurality system, you can only tell the robot your first-choice candidate; your robot has to sit out the micro-elections where your candidate isn’t on the ballot. In an approval system, where you’ve selected several unranked candidates, your robot doesn’t have enough information to vote in those elections where more than one of your candidates is on the ballot. In an instant-runoff system, your robot always knows how to vote the same way as you.

Kids seem to have a sense that there’s something a bit off about strategic voting; and, therefore, about systems that require it. (Among other problems, strategic voting is a bit like learning test-taking skills for the SAT: it provides an advantage for those who have thought of it, which may bias the election.) In the robot metaphor, strategic voting comes about only when your robot is too stupid to do what you want it to in every micro-election, so you have to decide what to tell it in order to get it to vote right in the micro-elections that you think are more likely to come up, or more likely to matter.

2. Primaries and Decision Theory

[This is unrelated to the first topic, except that they're both about elections.]

Let’s say you want to run for president. To do this effectively, you need a certain amount of manna (money, endorsements, and organizational backing); each bit of manna increases your chances of winning.

There’s a mana provider with a lot of huge amount of manna, who’s willing to make a deal with you: after you accept the terms of the deal (and only after), they’ll decide whether to anoint you (this is the process by which they give you all their manna); and if you don’t, you agree to drop out of the race.

This deal has a up side — that you’ve got more manna, and therefore you’ve increased your chances of winning the election if you’re anointed — and a huge down side — that if you accept the deal and the manna provider doesn’t anoint you, you’ve decreased your chances of winning the election to zero (because then you’ve promised not to run).

Let’s say you have a 20% chance of winning the election on your own, and that being anointed increases your chances by 20%. Then the payoff matrix looks like this:

 anointednot anointed
reject deal0.20.2
accept deal0.40.0

Now let’s say you have only a 50% chance of being anointed. Then your chance of winning the election if you reject the deal is 20% (in this case it doesn’t matter whether you would have been anointed not), and your average chance of winning the election if you accept the deal is also 20%. It’s not obvious whether you should accept the deal or not; it depends on your risk tolerance.

But now let’s throw a couple of other factors into the mix. Both of these factors have the effect that your chance of being anointed is correlated with your chance of winning the election.

First, the manna provider could attempt to anoint you exactly when your chances of winning are greater anyway (by using some tool, such as polls or an interim election, to estimate these chances). If instead of having a 20% chance of winning the election without anointment, you either have a 30% chance or a 10% chance (you don’t know which when you make the deal), and you’ll be anointed if it turns out (after you make the deal) that it was closer to 30%, then the matrix looks like this:

 anointment-worthynot anointment-worthy
reject deal0.30.1
accept deal0.50.0

The other factor that increases the correlation between being anointed and winning the election is that if you are not anointed, someone else is, and this decreases your chances of winning the election, say by 20% (but not to less than 1%).

Then the matrix looks like this:

 anointment-worthynot anointment-worthy
reject deal0.10.01
accept deal0.50.0

The mana providers, of course, are political parties; and this is why candidates join parties.

What’s in it for the manna providers? This is just strategic nomination, to avoid splitting the vote in a plurality voting system. Interestingly, strategic nomination is analogous to strategic voting, only proactive, and aggregated at the level of the political party.

1 These are really simple robots, and we can build them all by putting checkboxes or numbers on a paper ballot.

2 The other ways they differ are in how they many micro-elections there are; how they determine who runs in each of those; and how the results of the micro-elections are aggregated to determine the winner of the overall election.

Posted: February 5th, 2008
Categories: Math Education
Tags:
Comments: 1 Comment.

Adding the Easy Piece; or, The Metaphor of the Rock

The novice project manager cares about a program’s size. The experienced manager cares when it gets big.

Big programs are, from a developer’s perspective, slow. Slow not to run, but to develop: effortful to maintain, expensive to change. Half the job of a project manager is to keep programs small by keeping their requirements small (and half the job of an architect is to keep them small when the requirements are large); this is about the case when this isn’t enough.

Developing a program is like pushing a rock around a room. (The rock is called “code base”. The room is an irregular shape called “design space”, with “requirements” marked off along the wall.) Big programs are big, heavy rocks. They require more push, to get less far.

Sometimes you can get several people to push one rock. This works if the rock is the right shape – if it’s straight and wide, say, so that many people can push it the same direction, at the same time. Otherwise they will push at different angles, and the greater part of their efforts will cancel.


Sometimes, you can break the rock into smaller pieces – so that different people can push them, or so that you can push them separately, or so that you can abandon some pieces and use instead pieces that are sited where you’re going. (The advantage of a pre-sited piece’s location can outweigh the fact that it’s not quite the right shape.)

Sometimes you can polish the floor, or insert rollers, or employ a cart (use languages, platforms, practices, tools). Sometimes, though, you spend more time polishing the floor than you would have spent moving the rock; and sometimes the rollers end up aimed differently from where it turns out you need the rock. But even when these tricks work, they only increase the size of rock that’s counts as “big”. Some rocks are still big rocks.

This perspective – the size of the rock – is the static view of code size. It’s concerned with how to move rocks of a fixed size. The static> view is the right view for maintenance programming. It’s the right view for (most of) version three of a product, where most of the program is unchanged from version two. Often it’s the right view for version two as well.

For a greenfield project – a project where you’re (mostly) not modifying an existing system, but (mostly) starting from scratch – the static view is too limited. In a greenfield project, you’re not just moving the rock. You’re building it too.

(How do you build a rock? By fastening other rocks to it. Or sometimes by coating chicken wire with papier mâché, if you just need to know how it looks.)

Greenfield development sounds simpler. Instead of pushing the rock where it’s needed, you just build it there. There’s some work (pushing) that you don’t have to do.

But oh, did I mention that you won’t know where the rock needs to go until you’ve already built some of it? (Funny how often that isn’t mentioned.) In fact, you may have even less of an idea where to site the rock that hasn’t been built than one that has, because the shape of the rock helps determine the site, And if a rock takes long enough to build, the room may change too.

So, you’ve got to build the rock, and you’ve got to push it, and you could do these in any order (build some, push some, build some more, push some more), except that you won’t know where to push it until you’ve got some built. And just to make this harder – and more realistic – there’s some parts you can’t build where you start, but only where you push it to.

This is the dynamic view of code size: that code size changes over the course of a project. The fundamental question about dynamic code size is: Does it matter what order you build the rock? If you know you’ve got to add a piece, does it matter whether you add it at the beginning or end of the project?

And the answer is yes, it matters. Sometimes greatly. Sometimes enough to determine whether you can build, and push, your rock at all. The reason is because building the rock makes it harder to push.

Often, on a project, there’s a few pieces that you know at the outset need to be there. They’re standard parts, that need to be attached to every project. You know how to attach them. It will be comforting to do so.

(Sometimes these pieces have names like “localization”, “optimization”, and “scalability”; or “graphic design complete”; or “windows compatibility”; or “undo”.)

Some advantages of attaching these pieces early are: an easy sense of accomplishment, and a feature checked off. They simulate great and early progress. The disadvantage is that they increase project drag. Attaching them makes pushing the rock harder. Make it harder sooner, and you’ve made your trajectory like the orange line, and not the green one, below.

It’s not that you should never add these pieces first. Building and pushing rocks is engineering; and engineering is the art of the trade-off.

Here are some reasons to add a piece sooner. You don’t know if you’ll be able to add it later, or if you’ll have time if you wait, or how long it will take. (You want to front-load uncertainty and risk.) Or: you need to show the rock to somebody, and they can’t imagine what it will look like with the missing piece. Or: you can’t imagine this either. Or: knowing how to add a piece gnaws at you – it’s a distraction – and you can’t concentrate on harder work until you’ve added the easy piece. Or: the rock is useful only halfway built, and the piece is the useful one. Or: you’ll have to tear the rock apart to attach a piece later, and this is more work than pushing a bigger rock now.

Engineering is the art of the informed trade-off. These reasons to make a rock bigger sooner are (can be) good reasons. Weigh them against the cost of pushing a bigger rock.

Posted: February 2nd, 2008
Categories: Essays, Software Development
Tags:
Comments: No Comments.

Getting Lost

I like to travel in style. Two different styles, in fact: exploratory, and direct.

When I’m late to an appointment, I take the most direct, familiar, route I know. I don’t try any tricks — roads that vaguely ring a bell, or look like they might connect — I stay with what I’ve known.

But when I’ve time to spare, I get lost. Given a choice between a 15 minute route I know, and one that might take twice as long, I’ll take the road less traveled (by me). I’m paying for knowledge, with time.

I discover a lot of good routes this way — not always to the place I was going at the time, but often to somewhere I want to go later, when I’m in a hurry and wouldn’t have time to look for them. And, when I am in a hurry and I do get lost — because I’m coming from or going somewhere unfamiliar, or have to detour — I’m more likely to come across a place I recognize, and place myself back onto my mental map.

So maybe it’s too simple to say that I’ve paid for my knowledge with time. I’ve made a deposit (of time), that I can withdraw later. Knowledge is the loan note.

The same holds in programming, and project management, and software development. (These are some areas that are open-ended but set against a virtual landscape, and with which I’ve some experience.)

Often, as developer and project managers, we’re up against deadlines. Crunch time is not the time to risk something new.

But the rest of the time, it helps to take the detour, so that the next time you’re in a hurry and need something (a library, a technique, a language, a framework), you can remember where you saw it.

It helps to stay a little lost.

1 Neither is when you’re working on someone else’s dime, unless it’s your employer’s decision. (Doing this from time to time would often be a good decision, but it’s rare.) This is one reason I write libraries.

Posted: January 24th, 2008
Categories: General
Tags:
Comments: 1 Comment.

Why Write Open Source Libraries

1. Exploration. I can sample platforms and sample stretch languages without sinking my stakeholders if I fail. Also, it’s easier to try something radical in a small, green field project than in a big one.

2. Altitude training (link TBD). I can make myself jump through hoops that I wouldn’t feel ethical asking someone to pay me to jump through. I did this recently with Sequentially; the next time I needed to simulate concurrent processes in a more serious context, it was a lot easier.

3. Encapsulating components. My answer to Steve Yegge’s problem is to refactor my code into libraries. When I write programs that run on Linux, or the JVM, or a browser, I get those features, but the code sizes of those libraries don’t really count against me. Why not do that with my own code, too.1

This was the motivation for LzOsUtils and Fluently (both didn’t get to projects), most recently: they were part of other projects, but they were respectively large/tricky enough that I wanted to be able to compartmentalize them, and think about them separately.

5. The Golden Rule. I’ve benefitted hugely from open source projects; why not give back a little?

6. You can take it with you! I’ve written things that I want to use in more than one project; this is easier if they’re in library form. That was the motivation for LzTestKit (another didn’t get to project), most recently.

7. Fame and fortune! Just kidding. You get more fame from working on one project (if it’s the right one) for a long time. And there’s more fortune in straight consulting.

8. More days. I’m with Joel and Leo Babauta (ZenHabits): sometimes I can only work productively for four hours a day. The trick is to have more days. If I’ve got another project I can switch to when I burn out for the day on the first one, sometimes I can get another work day out of it. (Another trick for getting another day to move from the home to the office or vice versa, or to switch cafes.)

1 Interestingly, the extra work to some code up so that I never need to look inside it again (docs, test cases, examples) and can remember how it works years later is exactly the same work that I need in order for someone else to use it. I use to think I could take a short cut on things I use myself, but with enough going on or enough years in between, it isn’t true.

Posted: January 24th, 2008
Categories: Programming
Tags:
Comments: No Comments.

What Every Programmer Needs to Know About Category Theory

Posted: January 17th, 2008
Categories: Amusements
Tags:
Comments: 13 Comments.

The Programmer’s Food Pyramid

Programmer's Food Pyramid

Update: (1) There’s a discussion (at the moment) on reddit. (2) Thanks to FusionGyro for suggesting the name change to “revising”.

Buy on Zazzle:
Poster
Mousepad
Coffee mug

Posted: January 17th, 2008
Categories: Illustrations, Programming
Tags:
Comments: 26 Comments.

What I didn’t get to

Here are some of the weekend projects that I didn’t finish this year. These aren’t good enough to put on my project list or my sources page. Some of these aren’t even working, and some of them I might not finish at all (most of my weekends are spoken for). And some of them I can’t bear to look at (I’m not proud of the code, and don’t want to be judged by it…), but I’m making myself put them out there anyway. I feel bad for the neglected little things, trapped on my hard drive, and I’d like to let them see the sun, even if just briefly before they flicker out and die.

Libraries:
* LzOSUtils — jQuery-compatible ajax function, Flash->JS bridge with callbacks, declarative Flash 8 filter effects, console that reports to Firebug, dashed lines, Prototype-compatible string and collection methods, etc. Completely undocumented and fairly disorganized.
* LzTestKit — mocks and asynchronous and automated testing for OpenLaszlo; still pretty raw.
* HopKit — a “higher order programming kit”, for constructed chained APIs such as in LzTestKit’s mocks and expectations; still somewhat buggy and undocumented.
* MVars — a port of Haskell MVar’s to JavaScript. I realized that what I actually needed for real-world applications was an implementation of the join calculus (a la JoCaml). I haven’t written the join calculus version.
* Protodoc — I wrote this to extract the docs from the source files and to implement the live examples in Functional and Sequentially; it includes a version of the wonderful doctest, for JavaScript. I got part way through refactoring it into something that isn’t quite put together again. I haven’t decided whether to finish it or whether there’s an existing project that’s close enough.
* [No link yet] Updates to OpenLaszlo JSON and ropenlaszlo, from using them over the past year. (No, those links go to the old versions — I haven’t uploaded the updates :-(
* Implementations in Ruby and JavaScript of the awesome CFDG. I wrote these a couple of years ago, and really want to update and clean them up to point where I can donate them to Hackety Hack, or someone else who might use them.

Applets:
* TilesHTML port of my mid-nineties Java version (which was a port of my mid-eighties C version), uses the Canvas tag; probably doesn’t work in MSIE
* IFS — a few minutes of pair programming with my son to show him some stuff about matrices; probably doesn’t work in MSIE
* On this day — iPhone applet; the feed is down right now
* Force-directed layout for my home page — this was my experiment using HTML instead of Flash; I got discouraged when I saw how bad the frame rate for full-page animation is was even in Firefox, let alone MSIE (Safari rocks now, though!)

Plus a couple dozen essays that are half or three-quarters written (programming, software development, math education), a couple of AJAX presentations, and two workbooks for teaching abstract math at the elementary level. It takes me longer to write an essay than a program, though!

More weekends, please.

Posted: December 31st, 2007
Categories: JavaScript, Libraries, Open Source, OpenLaszlo, Projects
Tags:
Comments: 5 Comments.