An Algorithmic Lucidity

a blog

App Academy Diary, Week Four

Monday 7 October 2013— The main part of SedentaryRecord went pretty smoothly. I like my one-liner implementation of the has_many_through association better than the instructions' suggestion of writing a whole new query template; the TA Patrick pointed out that my version is inefficient (firing off two queries rather than one), but instead of writing the query-saving long version right away, I decided to try implementing validations first (one of the suggested extension ideas). That didn't go well at all; I spent a lot of time ineffectually hacking away at the problem but didn't even come up with anything worth committing!

Wednesday 9 October 2013— I did poorly on the assessment yesterday. There were eight SQL queries to write; the first five were trivial, but I bombed the last three because I'm a moron and didn't remember that the keyword for filtering aggregations was HAVING. I worked with William Ott on an ice-cream finder (which uses Google Maps APIs to print out directions to nearby ice-cream) and a Twitter client. Of course, it simply wouldn't do to write an ice-cream finder without using it to find ice-cream, so after class we took one of our program's suggestions and bought ice-cream at the Häagen-Dazs in the mall on Market and Fifth. Today I worked with David A.; we learned about routers and controllers.

mock cat-rental webpage showing a cat's photo and details: name, age, birth date, color, sex

Thursday 10 October 2013— Dear reader, suppose yet again that you're working on the great American dog-sharing site—loser! Sharing dogs is so last week; you should have predicted that by now, everyone who's anyone would be renting cats instead. That's why today Dean Yang and I used our prodigious knowledge of not just models, but also both views and controllers, to make a mock cat-rental site! It's like this: say you visit the URL for the page that displays all the cats. Your browser issues an HTTP GET request, which is handled by the Rails router: an instance of the CatsController is spawned, and its index method is called, which puts an array of Cat objects (instantiated by the ActiveRecord ORM from their representations in the database) in an instance variable, which is then made available to a process that uses a template to decide how to express the information about the cats in HTML, which is then sent back to your browser. Similar stuff happens to let you make a new cat, or edit an existing cat.

Sunday 13 October 2013— On Friday I worked with Nathan Holland again; we added users and authentication to the cat-rental site! It's like this: in the app/config directory of the source repository there lives a file named routes.rb, which which tells Rails what to do with requests! Like, routes.rb contains a line that says "get 'login', :to => 'sessions#new'", which means that if someone issues an HTTP GET request to /login at our application's domain, that what happens next is determined by the new method in the SessionsController. As it happens, all that does is send back the log-in form generated from the template at app/views/sessions/new.html.erb. When the user submits the form, a POST request is issued to /login, which gets routed to the create method in the SessionsController! That does a few things. First, it tries to find the user in the database using the supplied credentials (username and hash-of-password). If that doesn't work, it shovels a friendly incorrect-username-or-password message onto flash[:errors] and renders the log-in page again (including the message from the flash hash). But if the user was found, then it logs them in by setting their session token, storing their current-user status in an instance variable, shoveling a friendly "Logged in from #{location}" message onto flash[:messages] (the user's location can be determined using their IP and the Geocoder gem), and redirecting to the page with all the cats!

Having accomplished this feat, Nathan and I spent a lot of time trying to push the application to Heroku so that we could test things like how to handle a user being logged in on several devices at once, but Heroku dislikes SQLite, and various attempts at troubleshooting the issue all failed horribly.

App Academy Diary, Week Three

Monday 30 September 2013— Today's assessment was implementing Crazy Eights in accordance with the given RSpec tests. In the afternoon, I worked with Dan Quan on exercises from the SQL Zoo, which varied wildly in difficulty.

Tuesday 1 October 2013— Today I worked with A. J. Gregory again, this time on a cute Ruby program for interacting with a database. A few remarks follow. The first remark: I much prefer the %Q syntax for multiline strings over heredocs. The second remark: it turns out that using string interpolation to compose database queries is very bad, because it leaves you vulnerable to SQL-injection attacks. The third, and final, remark: you shouldn't name any of your Ruby classes "Data," because apparently this name is already used by a regrettably exposed implementation detail of the interpreter itself.

Saturday 5 October 2013— Dear reader, suppose again that you're building the great American dog-sharing site. One problem that you face is that the the most convenient way of storing data in the database isn't exactly the same as the most convenient way to manipulate data in your program. It would be nice to have some standard tool for translating the rows in your database table to occurrence of a particular class in your favorite programming language and back again, without having to futz with the syntax of the systematic questioning lexicon every time you add a new feature ... some sort of—occurrence–row matching ...

The Ruby on Rails framework (does anyone else think Ruby on Rails sounds like the title of an action movie about a woman named Ruby who has to fight spies on a train?—no?) includes a library called ActiveRecord for this purpose. Suppose your database has a users table for storing all the user data, and a dogs table for storing all the data about dogs. And suppose we want to say that each dog is owned by a particular user. We can do that by including an owner_id column in the dogs table; for each row in the dogs table, this column will store a number referring to a row in the users table, thus indicating the user that owns that dog. Columns like this that refer to another table in the database are called foreign keys, and we also want to tell the database to index them so that we can search them in logarithmic rather than linear time in the number of rows. Then, when we write the classes to represent users and dogs in our application code (these are called models), Rails gives us nice shortcuts to make it easy to retrieve (respectively store) their information from (respectively in) the database. In the User class, we say that a user "has_many :dogs, :class_name => "Dog", :foreign_key => :owner_id, :primary_key => :id", and we put a similar belongs_to statement in the Dog class (the belongs_to corresponding to a has_many always goes in the class whose database table contains the foreign key), and then everything is great forever.

On Wednesday I worked with Mainor Claros on a simple URL shortener, and on Thursday I worked with Scott Silver on models for a simple polling application. Yesterday the original plan was to have a solo day during which each of us would implement our own simplified version of ActiveRecord (... SedentaryRecord?), but at some point it was decided that the office was needed to host hiring day for the cohort before ours, so there was no class yesterday and we'll do SedentaryRecord on Monday of next week. I told myself I would get something educational done just the same (App Academy is providing value added in the form of guidance, connections, and a working environment, but if you're a long-time reader of An Algorithmic Lucidity, then you know that I know that the ultimate responsibility for internalizing knowledge must rest on individuals, not institutions), but I'm sorry to report that some of the more frivolous distractions of the internet (as well as a science-fiction novel that I purchased Thursday night on a whim at the bookstore inside the library in the city, which I had not set foot in since I think the March of 'aught-ten) proved too tempting that day. But fear not, dear reader!—for today and tomorrow are an entirely different story, in which your faithful correspondent will no doubt make tremendous progress in his quest for true knowledge of the nature of web development, as well as related matters of concern, like who would win in a fight between the MySQL dolphin, the Postgres elephant (PostgreSQLephant?), and the bird that the SQLite feather was taken from.

Sunday 6 October 2013— Yesterday and today I looked at the instructions for the project scheduled for tomorrow which I've been calling SedentaryRecord and started working on a Python version (including tests), which I've been calling SerpentineRecord. Why? Because ... because I can. And because even though this is a Ruby/Rails course, I've been toying with the idea of preferentially shooting for Python/Django jobs when this is over. My thought is that Ruby and Python are filling the same niche in programming-language space, so that in the long term, it's only worth specializing in one of them: really mastering a tool (not just the basic syntax, which is easy, but the technical minutia and ecosystem and everything) is costly, so you want to allocate your finite amount of effort into mastering an orthogonal set of tools, rather than many tools that do mostly the same things. So if I will ultimately have to choose, I'm inclined to go with my first love, Python, even if that's only an arbitrary artifact of what I happened to learn first. Is that wrong? Is it petty of me to care about the merely cosmetic issue of syntactic whitespace versus that execrable word end, even while Ruby's blocks are suffused with grace and power whereas Python's lambda statement is deliberately crippled precisely because of whitespace considerations?

I don't know. But in any case, my money is on the dolphin.

App Academy Diary, Week Two

Monday 23 September 2013— I rewrote most of the tic-tac-toe game yesterday; information-theoretically speaking, the board state is only 9 lg 3 ≈ 14.26 bits, but for better or for worse, I resisted the temptation to represent it as a two-character string. Still (still!) didn't get the AI working, though. Today was our first assessment: way too easy, I thought; we were given about an hour, and I finished in under half that. Then we had a lecture/Q&A period which I thought was too long, which covered the solutions to the assessment and default hash values. Why does anyone think lectures are a good idea? I'll confess to hanging out in the back and reading a little bit from A Farewell to Alms, which I bought on a whim on Saturday at Half-Price Books (which is a nice store, although you have to wonder whose idea it was to stock so many copies of Elliptic Partial Differential Equations and Quasiconformal Mappings in the Plane). At lunch I bought coffee and food at Starbucks and spent a little more time trying to debug the tic-tac-toe AI—still to no avail, but I'll get there eventually! (Tic-tac-toe itself is dross, but it's really important to get minimax right, because it should generalize to other games without too much trouble, and we're doing chess later this week.) Speaking of games on grids, today's project was to clone Minesweeper. I worked with Jeff Fiddler, who is the Jeff from Nevada (and not the other Jeff who tried to teach math in high schools but was frustrated with the overemphasis on standardized tests). It went really well; we used pretty Unicode symbols and even got around to implementing a cursor interface (which is way better than making the user enter coordinates)!

Wednesday 25 September 2013— Yesterday and today I wrote chess with Nathan Holland! Also, it turns out that the criminal scum who steal entire bicycles are not above stealing individual wheels, either.

terminal screenshot of a text-based chess game mid-play, using Unicode piece symbols

Thursday 26 September 2013— Today's exercise was to write checkers, alone (contrast to the pair programming methodology of previous days). I ... used structs to represent the checkers and moves? I like structs?

terminal screenshot of a text-based checkers game, with a numbered list of legal moves below the board

Saturday 28 September 2013— Yesterday was about testing. Novice programmers test their programs by running them and seeing if they give the expected results, which might be okay when your program is small and no one actually uses it, but then what happens when you wake up one day and you're in charge of maintaining a twenty-thousand-line application that people really depend on?

Enter automated testing. By writing code to test code, developers can save time and be confident that recent changes haven't broken existing functionality! (At this point a pedant smugly inquires whether this implies the necessity of writing tests for the tests, and tests for the test-testing tests, and so on ad infinitum. This arguably doesn't deserve a reply, but is in any case easily answered by the observation that we expect tests to be much simpler than the code which is their subject; it takes less information to specify what is expected of a procedure than it does to specify the details of the procedure itself.) In test-driven development, the practice is actually to write the tests first.

I paired with A. J. Gregory; after some simple exercises, our major task of the day was to write a five-card-draw poker game in the test-driven development style. I will confess that this did not go as successfully as the projects of previous days. Perhaps the art of factorizing the idea of a program into informative tests takes more than a day to learn? Or maybe we were succumbing to tiredness at the end of a very educational week, this fatigue being only a very minor sin characteristic of being human, for which we may yet be forgiven? I can't say. (Yet.)

Sunday 29 September 2013— Dear reader, suppose you're on a quest to write the Great American Web Application—maybe the latest, greatest dog-sharing site or something; I don't know. Your app is going to need some way to persistently store data—your users' screennames, emails, hashes of their passwords (use bcrypt!), their dogs to share, &c. This data isn't really part of your application proper, so it goes in a special separate file called a database, but it is that which your application operates on and fundamentally exists for the sole purpose of curating, so your app needs some way of talking to the database and asking it questions, like "Hey, Database! User #97109 wants to be friends with User #89012; write that down, huh?" or, "My dearest friend Database, when you have a moment, could you please tell me which dogs User #98471 has available to share?" But this is mere anthropomorphism; what protocol do you actually use to get your code to talk to the database? If only there were some standard vocabulary for asking questions of the database ... some sort of—systematic questioning lexicon ...

Right, so today I successfully installed MySQL after some troubleshooting effort (it turned out that I needed to apt-get the mysql-server metapackage, and not mysql-server-core-5.5), and got acquainted with it at the command-line. Data is organized into tables of columns and rows, like maybe we have a ponies table with columns for pony_id, name and pony_type, and one of the rows is 2 | Twilight Sparkle | unicorn, and if we want to update Twilight's type we say, "UPDATE ponies SET pony_type = 'alicorn princess' WHERE pony_id = 2" and if we want to just look at the earth ponies we say, "SELECT * FROM ponies WHERE pony_type = 'earth pony'".

App Academy Diary, Week One

Monday 16 September 2013— For the next couple months, I'm going to be engrossed in an intensive web development course offered by App Academy; it's pretty great! Part of the routine is to write end-of-day blogposts describing what we've learned; I guess we were "supposed" to start a Tumblr specifically for these, but that's dumb because I already have a blog, so I think I'll just put my updates here (updating the post throughout the week). Today was the first day! App Academy puts a lot of focus on pair programming: you have two people at a workstation; only the "driver" types, while the "navigator" offers direction (and then you switch roles). Today I was paired with Chris Evans, who is a nice guy who knows way more math than me! Today our task was a bunch of fairly straightfoward Ruby exercises: monkeypatch the Array class to do this-and-such, make a playable Tower of Hanoi game, that sort of thing. The most challenging one was part 15 of Test First Ruby: write a method that accepts integers and returns a string describing the number in words (so e.g. 259123 becomes "two hundred fifty nine thousand one hundred twenty three"). Chris and I finished the most important stuff on time and started working on the bonus project about solving mazes, but we didn't get too far with that in the time remaining.

Tuesday 17 September 2013— Lecture/Q&A ran to 1035 today, which I thought was way too long, but at least I learned about how to use #tap to build up an array. Today I was paired with Josh Foster, who is a nice guy who has been working as a business analyst for a few years! We did some more Ruby exercises, still rather straightforward (I expect most of the value of the course to come in later weeks, as we learn about SQL, Rails, &c., of which I know almost nothing). Our tic-tac-toe game (with a dumb AI) took a while to debug.

Wednesday 18 September 2013— I was a few minutes late today because a train ahead of the train that I was on had mechanical troubles! Today I paired with Jen Hamon, who is awesome and used to study geoscience! We implemented the guessing games Mastermind and Hangman, and then started working on A* search (picking up with the code about mazes that I started with Chris on Monday), also taking a detour to investigate some curious behavior exhibited by Ruby hashes with arrays as keys.

Friday 20 September 2013— Yesterday's themes were Procs and recursion. I paired with Ben Hass; our most challenging exercise was Word Chains: find a way to mutate a dictionary word into another of the same length by changing one letter at a time, with all the intermediaries also being valid words (e.g., duck to unprintable to funk to fund). The prompt even included suggestions ("Grow a new set, new_words, by calling adjacent_words on each of the words in current_words," &c.), but our implementation wasn't behaving quite right; the TA Flarnie Marchan pointed out that we were wrongfully discarding some of the discovered words (the idea of a queue was mentioned). On the evening train, I thought more about this and realized that the problem is really just a standard breadth-first search; I rewrote a much cleaner Word Chains after I got home. Graph search (breadth- and depth-first) was also today's theme; I paired with Kenny Chandrasekera. The first part of the day went smoothly, but we had more difficulty with the task of writing a better (in fact, unbeatable) AI for Tuesday's tic-tac-toe game. We first tried negamax, at my suggestion (I was familiar with the problem from having done basically the same thing in Python last year), but didn't get it right; then we switched to an approach involving building up the game tree explicitly, but didn't finish. (The entire tic-tac-toe program is such terrible code that I might just rewrite the whole thing this weekend.)

All Vows

"Avinu Malkeinu, we have sinned against you! Avinu Malkeinu, forgive us, bless us, grant us atonement!"

"Why do you bother? You're not a child. You've studied the history of our world. You should know that there's no one to grant you atonement."

"You don't know that! Science doesn't know everything. You can't prove that there's no Higher Power."

"As you say. But if there is a Higher Power, It clearly hasn't concerned Itself with the operation of the moral law."

"In this world."

"Yes, in this world. But surely it is this world that we must concerned with, for if there is a next world, we are too ignorant to speak of it."

"That is why it is also a teaching of my people that this is also a time for us to forgive each other for the wrongs we have committed in the past year, as well as seeking reconciliation with haShem."

"And you anticipate the same thing being necessary next year?"

"I don't understand. How could it not be necessary?"

"'Knock, knock.'"

Engineering Selection

This whole business of being alive used to seem so much simpler and less morally ambiguous before I realized that the strong do what they can and the weak suffer what they must, that it has always been thus and could not have been otherwise. The other day I was reading Luke Muehlhauser's interview with Steve Hsu, and Hsu says:

Let me add that, in my opinion, each society has to decide for itself (e.g. through democratic process) whether it wants to legalize or forbid activities that amount to genetic engineering. Intelligent people can reasonably disagree as to whether such activity is wise.

There was once a time in my youth when I would have objected with principled transhumanist/libertarian fervor against the suggestion that the glorious potential of designer babies might be suppressed by the tyranny of the majority.

I don't have (those kinds of) principles anymore. Nor faith that freedom to enhance will inevitably turn out to be for the best. These days, my thoughts are more attuned to practical concerns. Oh, I'm sure he's just saying that because it sounds nice and deferential to contemporary political sensibilities and he doesn't want to catch any more flak than he does already. Obviously, the societies than forbid it are just going to get crushed under the boot of history.

Think about it. The arrival of Europeans in North America didn't go very well for the people who were already here—and that was just a matter of mere guns, germs, and steel (in Jared Diamond's immortal phrase). What happens to our precious concept of democratic process when someone has the option to mass-produce von Neumann-level intellects to design the next generation of superguns, ultragerms, and adamantium-unobtanium alloy?

True Inclusiveness

"Even after racism, sexism, and speciesism have been eradicated, the work of social justice won't be done. We still live in a viciously existence-biased Society, which cruelly disregards the interests of possible creatures just because they happen to not have been created yet!"

"'Creatures'?—I see you're still mired in the insidious grip of of organism privilege! What about all the possible qualia-bearing processes like orgasmium or paperclip-manufacturing nanoware, which don't factorize into distinct entities? My friend, I say there will be no justice until Society's sphere of moral concern extends to all possible computations in inverse proportion to their complexity!"

Strategy

"Oh, I'm so nervous! What if I ... ? What if they ... ? Oh, what ever shall I do?"

"I keep telling you, man, you're making things way too complicated. Just think about what outcome you want, predict which behaviors will lead to which outcomes, and then perform the corresponding behavior."

"That's it?"

"That's it."

Quotations II

Just keep telling yourself: if they haven't started questioning what society tells them yet, then maybe they are not the one for you.

—"Pick-up Lines for Feminists" by Lesley Kartali

So, so what
I'm still a rock star
I got my rock moves
And I don't need you
And guess what
I'm having more fun
And now that we're done
I'm gonna show you tonight
I'm alright
I'm just fine

—"So What" by Pink

The cheaper people are to model, the larger the groups that can be modeled well enough to cooperate with them.

Michael Vassar

Lyrics to the Song About Having Sinned

I'm going to do it the dark way
I'm going to do it in my way
I'm going to quietly sulk
And write things on the wall
And always be lonely

I will try to do my share
Sorting papers in my lair
But don't ask me to come play
'Cause I'll ask you to go away

I'm going to go on with living
Observing, loving, and giving
And I will never know joy
Nor being annoyed
Knowing that I've sinned
Knowing that I've sinned

I'm going to do it the dark way
I'm going to do it in my way
I'm going to make myself pure
With my act and my word
Frozen in my controlling

I will ruminate and try to figure out the humans' nature
And I'm looking for what's right
No matter if it is what I'd like

I'm never going to have a boyfriend
I'll always talk about the end
I will walk through halls
And pass through walls
Knowing that I've sinned
Knowing that I've sinned

Online Dating Profile, First Draft

25 / M / Straight / Single Walnut Creek, California

My self-summary

It hardly seems fair to ask for a self-summary—how could the rich tapestry of a human mind (with all its hopes, fears, memories, anticipations, and quirks) possibly be summarized in a mere paragraph? Or maybe that's a cop-out, a facile rationalization offered not because it has any chance of being believed, but because the real truth is too terrible to face: maybe the real reason one finds oneself reluctant to write a self-summary is not that there's too much to say (and therefore, that to say anything in particular would leave out too much and be a contemptible misrepresentation), but precisely that one fears there is too little: if we actually knew how much of our behavior could be predicted by simple programs informed by broad demographic data, a few personality parameters, and a small correction term for subcultural memetic noise, would our self-esteem survive the blow? What does it mean to be human in an inhuman universe, to hold true to one's ideals even after formulating the now-dominant hypothesis that those ideals were just folderol evolved to cover up the unavoidable responsibility of action in a world of crazy talking monkeys?

I don't know the answers. But I want to work to find them out. To face them, together, with you.

What I'm doing with my life

(Written 30 August 2013.) This autumn, I shall be attending App Academy's web development course, after which I shall seek employment as a programmer.

I'm really good at

starry-eyed idealism, reasoning under uncertainty

The first things people usually notice about me

My ... hair? My desperate and ineffectual attempts to signal how "smart" and "creative" I am? But probably my hair.

Favorite books, movies, shows, music and food

Text: collected works of Greg Egan and Eliezer Yudkowsky, Atlas Shrugged (it's not what it looks like, I swear)
Television: My Little Pony: Friendship Is Magic, Star Trek (TNG, DS9, VOY)

The six things I could never do without

internet access, mechanical pencils, the knowledge that it's easier to ask forgiveness than it is to get permission, em dashes, the magic of friendship, the global economy, being forgiven for listing seven things when I was only given permission for six

I spend a lot of time thinking about

Consider reading my blog to get an idea of the sorts of thing I think about.

On a typical Friday night I am

doing something wholesome and virtuous

The most private thing I'm willing to admit

... pass?

I'm looking for

  • Girls who like guys
  • Ages 19–30
  • Near me
  • For new friends, long-term dating, short-term dating

You should message me if

and only if it turns out that messaging me is the right thing to do

do/end Macros for Emacs

Dear reader, Ruby is a pretty okay programming language, but I have to say I feel ambivalent about the use of do and end as block delimiters. (Contrast to braces in C/Java/&c. or indentation in Python.) Three keystrokes just to close a block?! Scandalous!

Or maybe ... not-so-scandalous. For two or three characters need not imply two or three keystrokes; one need only configure one's editor with convenient bindings for the insertion of do and end. For example, pasting the following code into one's Emacs init file assigns M-[ (respectively M-]) to insert the text do (respectively end), much as one would type Shift-[ (respectively Shift-]) for an open- (respectively close-) brace, except with Alt ("Meta" in Emacs parlance) instead of Shift—

(fset 'block-do
   "do")
(global-set-key (kbd "M-[") 'block-do)

(fset 'block-end
   "end")
(global-set-key (kbd "M-]") 'block-end)

I guess this would also be useful for like, Lua.

I'm a Moron

It's always tempting to make excuses for our past selves, to tell a story about how, despite the appearance of continual failure and waste, we were actually in the right all along.

It's not true. If we were really in the right, we wouldn't need to strain to tell a complicated story explaining why; it would just be obvious from appearances.

When I find myself tempted to tell stories, it takes a deliberate effort to remind myself to be honest, but it's important. I was a fool; I was worse than a fool, and maybe I happened to get away with it, sort of, so far, but there's so much that I should have known, should have guessed, should have realized, should have considered. Of course there's no use dwelling on it overmuch, for we cannot make decisions about the past. But that's not the same as it being okay that it happened that way. It's not.

Measure

In a sufficiently large universe, everything that can happen happens somewhere, but it's clearly not an even distribution. Flip a quantum coin a hundred times, and there have to be some versions of you who see a hundred heads, but they're so vastly outnumbered by versions of you who see a properly random-looking sequence of heads and tails that it's not worth thinking about: it mostly doesn't happen. When you write a computer program, or build a bridge, or just think something, we might prefer to take the viewpoint that you're not creating anything so much as you are instantiating that pattern locally, thereby increasing its measure in the multiverse: there might be other ways for that program, that bridge, that thought to come about somewhere, but it's getting some of its support from you. Decisionmaking is about exerting some control over the distribution of measure over patterns in the multiverse: agent-like patterns select actions so as to allocate measure to their preferred patterns. Maybe there are some versions of me with an ice-cream cone that form by chance, or are deliberately created by alien civilizations investigating how humans respond to ice-cream, but if I get an ice-cream cone, it's mostly because humans evolved and then developed cultures which domesticated dairy cows and cultivated sugar and so on and so forth until eventually I was born and grew up and put effort into acquiring ice-cream. When you decide, you help determine the distribution of what happens to the sections of the multiverse that depend on copies of your decision—choose carefully.

The Future of Ideas

William Gibson famously said, "The future is already here—it's just not very evenly distributed." It's easy to imagine a science-fictional fantasy world where everything is made of diamond and plastic, and literally everyone has their own brigade of robots, spacepacks, and jetcars to do their bidding, but as Gibson points out, the real world doesn't actually work like this: there's nothing contradictory about the high technology allowing you to read this post existing in the same world where millions of others are starving, thirsty, and illiterate. The Earth is just a very big place compared to what we know how to imagine personally; the wealth and wonders that exist in some places, don't exist everywhere. As long as this is true, we should expect variance in wealth to increase, as new toys for the rich get invented faster than the basics can be provisioned for everyone; Carlos Slim can purchase extravagances that hadn't been invented in the days of Cornelius Vanderbilt, but dying of malaria is the same as it's ever been.

A similar thing could be said about knowledge and ideas. Human civilization has been rapidly accumulating knowledge, but we're not getting proportionately more capable as individuals. People typically don't have the resources or inclination to learn deeply outside of their own specialties, and many never get to master any specialty at all. There's nothing contradictory about our brightest scholars seeing more deeply into the true structure of the world beneath the world than the uninitiated would have ever conceived possible, while at the same time, the masses labor under the most primitive of superstitions. As long as this is true, we should expect variance in knowledge to increase, as the cognitive elite continues to advance the frontier of the known faster than the basics can be taught to everyone; our master biologists know more about the nature of life than their analogues in the days of Darwin and Wallace, but to the proletariat, "God did it in six days" probably still sounds like as good of an explanation as it's ever been.

Plurals of Coinflip Outcomes

We speak of the outcome of a coinflip being heads or tails, which are surely singular nouns in this context, despite being derived from the plural forms of head and tail. So when we flip a coin twice and get heads (respectively tails) twice, should we describe the outcome as two heads (respectively tails), or two headses (respectively tailses)? I feel like you could make a logical case for the latter, but I guess the former does sound more natural?