Look, that would be weird, but itās possible, and Ruby doesnāt do anything to help you out here, and I feel like it should.
Whatās happening?
Youāre calling the instance method #each of the DatabaseResult class.
And itās just not doing anything at all and doesnāt even know you gave it a block.
Cool.
Brief digression time.
That method has an āarityā of zero.
How do I know that?
What does it mean?
It means that the method takes zero arguments.
But when we count the arity, weāre not considering blocks, because blocks are a special, weird kind of argument, where you can provide it or not and itās kind of outside of the method signature.
You can have methods that takes a block and uses it, and its arity will still be zero:
Iāll tell you: it doesnāt.
Even though it sort of feels like it should.
These versions of the method really require you to pass them a block, which you just have to know.
If you forget to pass a block, you get a nasty error:
candle4.rb:9:in `block in each': undefined method `call'for nil:NilClass (NoMethodError)
from candle4.rb:8:in `each'
from candle4.rb:8:in `each'
from candle4.rb:27:in `<main>'
candle5.rb:9:in `block in each': no block given (yield) (LocalJumpError)
from candle5.rb:8:in `each'
from candle5.rb:8:in `each'
from candle5.rb:27:in `<main>'
No block given.
Local jump error.
Sure.
Thatās Ruby trying to be helpful and I appreciate that.
Ruby helps you (by raising a helpful error) when you donāt provide a block, but you were supposed to.
But it doesnāt help you when you do provide a block, and you werenāt supposed to.
Rubyās like, yeah, sure, just provide a block wherever you want, this is a free country.
If you wanted to change this behavior in your code, and get helpful errors when your blocks are unexpectedly not invoked, you could do something like this:
I donāt think you should do this, but you could, and I kind of wish Ruby just did it automatically.
I know itās an impractical request, because there are valid use-cases where you might pass a block to a method, and the method just assigns it to an instance variable without calling it, but it promises to call it later.
But maybe Ruby could detect that somehow.
Iām just thinking out loud here.
Iāve seen tests where assertions lived in blocks, and the blocks were never being called, so they werenāt actually asserting anything.
Iāve seen configuration being done via a DSL in a block, except the block wasnāt being called, so the defaults were being used.
I guess what Iām saying is itās a little weird to me that blocks arenāt treated like ordinary arguments.
If they were, youād get an ArgumentError if you forgot to provide it or if you provided it and it wasnāt expected.
Note: Iāve expanded on these ideas in a conference talk, which you can see here.
I recently learned about a feature of the Ruby programming language that has shaken me to my very core.
Consider this code:
# dog.rbclassDogattr_reader:namedefinitialize(name)@name=nameorraiseArgumentErrorendenddefget_dogDog.new("Milo")endthing=get_dogifDog===thingputsthing.name+" is a dog"end
What happens when you run this code?
Feel free to try.
But Iāll tell you.
$ ruby dog.rb
Milo is a dog
This code seems pretty resilient to unexpected runtime errors.
Looking at the code, it seems pretty reasonable to believe:
when we have an instance of Dog, we will be able to send it the message name and get back a String
Up is up.
The sky is blue.
Weāre living in a society.
Well, ok, but we canāt actually assume that the value will be a String, because it doesnāt check that.
If we change our definition of get_dog, things blow up:
defget_dogDog.new(["Milo"])end
$ ruby dog.rb
dog.rb:15:in `<main>': no implicit conversion of String into Array (TypeError)
But, OK, at least that error message is pretty good.
This is user error.
When we write thing.name + " is a dog", weāre expressing some amount of faith in ourselves that we expect a String, because values of other types donāt necessarily respond to a + method.
This is a leap of faith that weāre all willing to make when we use Ruby.
Other languages eliminate the need to make that leap of faith by checking types when you compile your code, but Ruby doesnāt do that.
And thatās fine.
So maybe our expectation should be:
when we have an instance of Dog, we will be able to send it the message name and get back a truthy value
And weāll just remember to provide Strings.
Maybe weāll write a comment indicating the expected type of the parameter.
IMO this one is a bit pedestrian.
Yeah, fine, you can just remove instance variables on random objects if you want to.
Of course.
My spirit is already broken, this isnāt meaningfully worse.
So letās just try to say something that we donāt have to take back right away:
when we have an instance of Dog, the code in the initialize method must have run
Right?
That has to be true.
Weāre living in a society, remember?
Nope:
defget_dogDog.allocateend
That results in this output:
$ ruby dog.rb
false
nil
What the hell is this?
This is the thing I mentioned at the beginning that I learned recently.
When we create new objects in Ruby, we usually use the new class method.
Notably, we donāt call the initialize instance method ourselves, although thatās what we are responsible for defining.
Ruby handles calling that method for us.
But before Ruby can call an instance method, it needs an instance, and thatās where allocate comes in.
It just makes an instance of the class.
And youāre allowed to use it in your Ruby code, if you want to.
(Hat tip to John Crepezzi whose blog post explains this really well)
If you do, you get back a normal instance of your class in every way, except that the initialize method hasnāt run.
You can even call your own initialize method if you want to:
when we have an instance of Dog, itās a good dog
Basically: š¤·āāļø.
Thatās the bottom.
Thatās as far as I know how to go.
Maybe thereās more.
Please donāt tell me.
I want to emphasize: this is not a criticism of Ruby.
Iām only faux-alarmed.
Ruby is a springy ball of dough.
Itās whatever you want it to be.
All of these features are sharp knives you can use or abuse.
As Iāve been learning another language which feels much less pliant, Iāve started to notice things about Ruby that never occurred to me before.
When I write Rust, I take some pleasure and comfort from the rigid rules.
Itās more possible to use words like āguaranteeā and āsafetyā in Rust-land.
I learned a neat shell script refactoring strategy yesterday that Iād like to share.
First some background:
I used to use a rubygem to help me write this blog.
When I wanted to create a new post called āchainable shell functionsā I would have run:
bin/poole draft "chainable shell functions"
And it would create a file called _drafts/chainable-shell-functions.md with some metadata in the first few lines.
Yesterday I got the urge to try replacing that rubygem with a custom shell script which does exactly the same thing.
I am an enthusiastic novice shell scripter.
Iām vaguely aware there are different dialects of shell scripting and that Iām probably using the wrong one.
Really Iām not expert in this stuff.
But while writing this one I learned something interesting that Iām going to share with you now.
Here is the first draft (annotated with comments for your convenience):
#!/usr/bin/env bash# fail fast if any expression failsset-e# read all of the arguments into a stringtitle="$*"# OK don't worry about this gnarly line, I'm going to break it downslug=$(echo"$title" | sed"s/ /-/g" | tr-dc'[:alnum:]-' | tr'[:upper:]''[:lower:]')# the file we're going to createfilename="./_drafts/$slug.md"# create the folder if it doesn't already existmkdir-p _drafts
# stop if the file already exists -- I don't want to overwrite an in-progress draftif[[-e"$filename"]];then
echo"$filename already exists"exit 1
fi# create the draft by piping a string into a fileecho"---
title: $title
date: $(date'+%Y-%m-%d')
---
Alright, this is where your post goes.">$filename# Print a successful messageecho"Created $filename"
OK did you read that?
Great.
So you saw that line I promised I would break down?
The idea with that line is that I want to take the input, which is the title of the post, and figure out what is an appropriate filename for the post.
Iām figuring that out by applying a series of transformations to the title:
echo "$title"
just repeats the title, directing the output into a āpipeā, which the next command will read
sed "s/ /-/g"
sed is a āstream editorā; it reads in a stream of data and prints out a stream of data
here weāre using regular expressions to āsā or substitute all occurences of a space with - (hyphen)
we want hyphens because they make for nicer looking URLs than spaces, which get escaped to %20.
the g at the end means āglobalā; without it, we would only subsitute the first space
tr -dc '[:alnum:]-'
tr is short for ātranslateā
-d means ādeleteā
-c means ācomplementaryā
this command means ādelete all the characters that complement this set of charactersā
in other words, ādelete all the characters that arenāt alphanumeric or a hyphenā
tr '[:upper:]' '[:lower:]'
ātranslateā again!
this time weāre translating all of the upper-case letters to lower-case letters
Finally, we stop piping the output to the next command, and weāre done, so the result is saved in that local variable.
OK so thatās a lot going on in one line, and because of the compact nature of these commands, itās not super readable.
In other languages, when I have a lot going on in one function, I want to split out smaller, well-named functions.
Can I do the same thing here?
At first I wasnāt sure.
I knew it was possible to write functions that received arguments by checking $1, $2, etc in the function,
but I wasnāt sure how to make them āreturnā valuesā¦
After a little googling I learned: you can just write a shell function that calls commands that read from a pipe, and pipe things to that function.
Let me show you what I mean.
Hereās the second (and, frankly, final) draft:
#!/usr/bin/env bashset-efunction dashify(){sed"s/ /-/g"}function removeSpecialChars(){tr-dc'[:alnum:]-'}function downcase(){tr'[:upper:]''[:lower:]'}title="$*"slug=$(echo"$title" | dashify | removeSpecialChars | downcase
)filename="./_drafts/$slug.md"mkdir-p _drafts
if[[-e"$filename"]];then
echo"$filename already exists"exit 1
fi
echo"---
title: $title
date: $(date'+%Y-%m-%d')
---
Alright, this is where your post goes.">$filenameecho"Created $filename"
This is kind of fine, but it has one problem:
each time you reference dog, youāre calling the dog method,
which queries the database each time itās called,
so youāre querying the database over and over,
when you really only need to do so once.
Better to write it like this:
defdog@dog||=Dog.find(@dog_id)end
Here youāre still calling the dog method over and over, but now itās āmemoizingā the result of the database query.
But what does that mean?
Hereās a more verbose version of the dog method that does the same thing:
defdog@dog=@dog||Dog.find(@dog_id)end
You can see that ||= is a syntactical shorthand similar to +=.
In case youāre unfamiliar with +=, hereās an example.
These two statements are equivalent:
count=count+1count+=1
Hereās an even more verbose version of the dog method that does the same thing:
defdogif@dog@dogelse@dog=Dog.find(@dog_id)endend
The goal here is to avoid evaluating the database query more than once.
The first time the method is called, the @dog instance variable is not defined.
In Ruby, itās safe to reference an instance variable that isnāt defined.
It will return nil.
And nil is falsey, so the database query will be evaluated, and its result assigned to the instance variable.
This is where things get interesting.
Ponder this question:
does this memoization strategy guarantee that the database query will only be executed once, no matter how many times the dog method is called?
It doesnāt.
Why????
Iāll tell you.
What if there is no dog with that ID? Dog.find(4000) returns either a dog, or nil.
And, like we said earlier, nil is falsey.
So hypothetically, if our perform method looked like this:
defperformdogdogdogdogdogend
ā¦ then we would execute the database query five times, even though we made an effort to prevent that.
This is actually totally fine, because our perform method isnāt written like that (again, that was just a hypothetical).
Our perform method only calls the dog method more than once if itās truthy, so thereās no problem here.
memoization using defined?
Letās consider another example, where things arenāt as hunky-dory.
Hold please while I contrive one.
OK, Iāve got it.
Letās say we only want to groom a dog when he or she is unkempt.
When she logs into our web site, we want to pepper some subtle calls to action throughout the page encouraging her to book an appointment.
Weāll need a method to check if she is unkempt, and weāre going to call it a few times.
It looks like this:
Here our goal is to prevent doing the expensive database query (Hair.count_for(self)) more than once.
Ponder this question: does our memoization strategy accomplish this goal?
Answer: it does not.
What?????
I know.
Let me show you.
You can try running this Ruby script yourself:
$count=0classHairdefself.count_for(dog)$count+=1puts"called #{$count} times"2_000_000endendclassDogHAIRS_THRESHOLD=3_000_000defunkempt?@unkempt||=Hair.count_for(self)>HAIRS_THRESHOLDendenddog=Dog.newputs"Is the dog unkempt? #{dog.unkempt?}"puts"Is the dog unkempt? #{dog.unkempt?}"
It outputs the following:
called 1 times
Is the dog unkempt? false
called 2 times
Is the dog unkempt? false
In this script, I have a fake implementation of the Hair class.
Itās meant to demonstrate that the count_for method is being called more than once, even though we specifically tried for it not to.
So whatās going on here?
Well, in a way, everything is working as itās supposed to.
The first time we call the unkempt? method, the @unkempt instance variable is not defined, which means it returns nil, which is falsey.
When the instance variable is falsey, we evaluate the expression and assign its result, false, to the instance variable.
The second time we call the unkempt? method, the @unkempt instance variable is defined, but its value is now false, which is also falsey (which you have to admit is only fair).
So, again, because the instance variable is falsey, we evaluate the expression and assign its result, false, to the instance variable.
Shoot ā that kind of makes sense.
So what to do?
Hereās another way to write this:
This approach uses Rubyās built-in defined? keyword to check whether the instance variable is defined at all, rather than if its value is truthy.
This is more resilient to the possibility that your value may be falsey.
I wish there were a more succinct way to write this, because I think itās generally how you actually want your code to behave when you use ||=.
To be fair, you can avoid defined? and instead write this method like this:
I made a screencast to share a fun idea I had while exploring a bit how git works.
You may know that when you use git to track a project, it creates a hidden .git directory with some files in it.
But what actually goes on in there?
And when do the contents of those files change?
Hereās the idea: I know a tool for tracking the changes to a directory over time, and that tool is git itself!
So in this screencast you can see me try and do that ā I initialized a git repository, which created a .git folder, and then I initialized another git repository within that .git directory.
I still donāt have a really great understanding of how git represents the data, although Iāve read Mary Rose Cookās very good essay about this topic Git From The Inside Out, which does contain those answers (I read it a while ago and forgot the details).
But I feel like I learned a few things thru this little experiment, specifically about when they change.
Note: this is a sort of personal story about a stressful experience. Iām writing it because I want to remember it.
Last week I was on vacation in Berlin, and this week Iām jumping back into my work life.
Both things are great!
In-between something wasnāt great.
I had a few hours laid over in Copenhagen before my flight into JFK.
I spent them doing laps around the terminal looking for something vegetarian to eat.
While walking I listened to a few episodes of the Bike Shed podcast, which Iām a few months behind on.
Eventually I found and ate some nachos, which I happily ate while reading Squirrel Girl.
All that, fine.
The flight was uneventful.
Norwegian Air.
I got around to watching Carol.
I probably need to rewatch it on a bigger screen.
Solid.
Slept a bit.
So far so good.
A husky American in a striped polo shirt sat on my right.
A young Swedish woman slept on my left.
None of us really talked much, except mild small talk about whether you need to declare spices at customs.
(She asked me.
I had no idea, but I said eh, you can probably get away with not mentioning it.
I think she declared anyway.)
She told me sheās a student on her way to Arkansas to study abroad, and sheās just transfering in New York.
When we landed, around 8pm, we couldnāt disembark right away.
The pilot cited weather.
They played music.
People kept watching movies and TV.
I think I didnāt disembark until around 9:40pm.
I remember joking to the Swedish woman that if it wasnāt for the music, I might be kinda impatient, but with it Iām pretty content.
The playlist ran out of songs and looped back on itself.
I only noticed because it was mostly upbeat pop songs, but then also Blue Bucket of Gold by Sufjan Stevens, a very slow and beautiful song about feeling lonely and alienated.
And I didnāt realize it was Sufjan Stevens (who I really like) until it came on a second time and I laughed at how random that is.
Then I fell asleep for a bit.
When we did start to disembark, I put on my big black backpack, but then we were asked to sit down again, and I took it off.
A few minutes later, people started moving again and we flowed off the plane.
I said āthanksā to the flight attendants, thinking they were probably getting a lot of shit from impatient passengers and strolled down the jet bridge (a term I only learned this week) toward customs.
I was kind of tired; Iād just been napping with my forehead against a television.
All I was thinking about was how to get home, weighing the choice of springing for a cab or just taking the train.
But first, customs.
I got on the end of a long line, putting in my earbuds and selecting Hotline Operator, a song which bristles with an impatient energy.
Because people were impatient, they pressed forward, as though becoming dense would make the line move faster.
Some others got on the stationary moving sidewalk to move farther ahead in the line.
I remember thinking it was like people driving on the shoulder of a highway to pass you.
Without putting a lot of effort into hanging back, I was pretty much at the way back of the line.
I couldnāt see all the way to the front.
I started thinking about taking off my heavy backpack with the expectation that I would be standing for a while.
When I expect to be bored for a while I kind of let my body go into autopilot and let my mind wander for a while, and thatās what I was starting to do.
Iām not sure what exactly snapped me back to reality, but the next thing I knew I was running, and so was everyone else.
In only a few seconds, hundreds of mostly stationary people facing one way turned and ran the other way, toward me.
You donāt really question that, you just go.
You donāt really have another option.
Not that youāre thinking at all.
The gush of humanity I was swept up in elected to run down a jet bridge.
There were several abandoned rolling suitcases blocking the path.
I knew people were charging behind me and were probably going to stumble on them, and I grab one by the handle and run with it in my hands.
At the entrance to the plane, I set it to the side.
This is the one good deed I did all night, I think, and I still left a bunch behind.
The Air Korea flight attendants were confused and kind of angry that these people were rushing onto their plane.
āWhat is happening??ā one asked the streaming crowd.
I told her the crowd has panicked and I didnāt know why, but it seemed like maybe thereās a shooter, but I didnāt know.
That seemed like the only explanation.
People in the front must have seen something and bolted, understandably.
What else could it be?
No one needed to say it ā we all knew, right away.
And people did start saying it.
I felt incredibly alert.
I would notice later my mouth was dry as a bone.
I paused in first class and moved into a seat to get my bearings.
Some came panting, others crying onto the plane, everyone flowing into the back as though for a takeoff.
I saw a woman calling for her son; they were separated in the chaos.
āWhat does he look like?ā, someone asked.
āHeās ten years oldā, she said.
I saw another mother holding her young, sobbing son to her stomach and telling him, āItās okay. Itās okay.ā
I wrote a text to my family:
Iām safe.
There was a a panic at the airport.
Crowd ran.
Iām sitting on an airplane right now.
Different one than I disembarked from.
Followed running crowd.
No signal.
Not sure if this will send.
Writing at 22:07 ET
Will update.
I am safe
I see now that it went through ten minutes later.
I wasnāt sure how safe I was.
Even on the plane, I felt exposed and at risk.
I was tempted to move to the right side of the plane to be just a little farther from the terminal.
But I needed to send that.
I saw the Swedish woman, shocked, move into the back of the plane, and I joined her in a seat.
āWhat the fuck is going on?ā I asked, and she didnāt reply.
Somehow, for some reason, the flight attendants communicated to us that it was time for us to get off the plane.
I donāt recall if we were instructed to go back down the jet bridge.
I donāt recall if the plane was becoming full of people.
What happened next is that people started opening the emergency exits.
Maybe thatās why.
They couldnāt manage to open the emergency exit in the rear of the plane.
I recall seeing some kind of component hanging by a wire, and a flight attendant poking at it like, āwell, this one isnāt openingā.
āStay calmā, an elderly woman urged everyone.
The mid-plane emergency exits were both open, and the one on the left (facing the terminal) had a slide going down to the tarmac.
The one on the right had no slide, it was just open twenty something feet above the hard ground.
One flight attendaant stood spread-eagle in front of it to make sure people knew not to go that way.
Another stood by the slide, metering us out, telling us when to go.
The two women shouted to each other in Korean over the din.
Ahead of me, people were sliding down to the tarmac and jogging around a corner of the terminal.
I jumped, slid, and hit the ground running after them.
I passed a man taking shelter in a corner behind what might have been gas tanks, and I was tempted to join him, but I ran on with the bigger group.
Around the corner, we reached a barbed-wire fence.
I assume the idea is to make it harder to access the tarmac, but in the moment many people felt trapped.
I saw some people pushing a bright yellow dumpster toward the fence, with the idea that they could use it to jump the fence.
I took several photos from this point on, nearly all of which came out blurry beyond interpretation.
My sister texted me:
Max?
The rest of my family was in London, and sleeping, but Gaby was awake.
I told her I was safe and to tell me if thereās anything in the news about JFK.
Then I fired off a tweet:
I am at JFK airport. I am safe. Something is happening. Please text or mention if you know what. Crowd is panicking
I sent tweets intermittently for the rest of the night, most of which have typos because I wrote them quickly while afraid.
People werenāt sure what to do.
Personally, my plan was to stay put and wait for a hero.
I think some others probably felt the same way.
Opinions varied on where was safest to physically stand.
There was a large, open garage (I think thatās what youād call it, although I donāt recall seeing any vehicles), which some stood within.
This seemed like a good idea in the event that attackers came around the corner.
Others seemed suspicious that attackers might come from inside the garage, and stood vigilant, eyes darting between the garage and the tarmac.
Around this point a policeman came and told us to follow him around the corner back toward the customs area, where there are more police.
When he saw the people pushing the dumpster he shouted after them, something like, āYou are NOT going to do that.ā
A woman asked him what the plan was, said she wouldnāt go unless there was a plan.
He made the point that he was going to walk us there, and what, is he going to willfully put himself in danger?
This argument, an appeal to a relatable self-preservation, seemed to make sense to the crowd.
We started cautiously walking.
We were all hugely reluctant to move back in the direction of airplane and customs.
As we inched forward I saw silhouettes of figures in the windows of the terminal, some walking, some standing and watching us.
I didnāt know what to make of that.
A child let out a screaming cry, and everyone immediately turned to run back toward the corner, which had somehow started to feel safe, and not worth leaving.
Crowd is still and then turns to run like a herd. "It was just a child's scream" no need to run someone says
They havenāt found shooter or anyone injured as of now
Me:
100%. I feel safe right now
Battery pack baby
Slowly the policeman and some other airport staffers coaxed us back toward customs, and two doors which went directly from the tarmac into the big open room.
People were very reluctant to enter.
I had the sense that the room must be safe if Iām being told to enter it, and I went in.
People reluctant to go inside but I'm in and so are many. Air conditioned. Noisy chatter
Inside, I was shocked to find that there were already dozens of people queueing in an orderly fashion to go through customs.
I couldnāt see if anyone was actually at the desks to process them.
Beyond the desks, the airport seemed well-lit and deserted.
I didnāt feel safe getting on the line; Iād seen this crowd turn into a stampede in seconds.
I stood near the doors and tweeted this:
Until further notice I am more afraid of the crowd being inside and panicking ahain
And a few minutes later, it happened.
Something spooked the crowd and they bolted for the doors, feeling safer on the tarmac.
I think they believed an active shooter must have still been in the terminal, even though some semblance of order was beginning to formā¦
Outside I tweeted this (compare the timestamp to the previous one):
Crowd panicked and ran outside. Pipe of people at doorway. Outside again
I meant āpileā, not pipe.
Hereās what I saw:
At this point I saw people were starting to move way in the opposite direction of customs, to the far edge of the tarmac.
I saw why: there were 2 shuttle buses there, and people were getting on them.
I walked under an airplane toward the buses.
A crowd formed here, hopeful.
Weāre getting outta here.
The two buses became full and left.
I have no idea where they went.
We waited, hopeful that more would come.
I took the opportunity to update Gaby, tweet a few updates, and search for any news.
My twitter feed was full of people talking about the Olympics and or the election.
I remember feeling slightly stunned that the whole world wasnāt talking about me.
Every minute or two I got notifications of people sharing or replying to my tweet updates.
Some folks mentioned or direct messaged me asking questions and providing updates from police scanners and news reports.
No one knew anything.
One BBC reporter mentioned me asking if I wanted to do an interview when I feel safe; a reporter from a talk radio show asked me if I could confirm that shots were fired.
I felt the need to offer this update:
Just to repeat the point, I didn't personally observe any guns or packages, just panicked crowds, and I ran with them. Still feel safe
I didnāt know if there was a shooting or not.
I wanted to believe there hadnāt been.
I knew there was a lot of confusion both among the passengers on the tarmac and among the people replying to my tweets.
I couldnāt clear away the confusion but I wanted to emphasize to anyone who was following the story not to assume the worst.
After more than 20 minutes of standing restlessly and comparing confused notes with each other, three more buses arrived.
I got on the last bus.
The last person to board the bus before the door closed was a young guy who reminded me of my 20 year old cousin Eric from Georgia.
He asked if I knew anything.
Said his phone died.
Said he got separated from his sister.
āHow old is she?ā I asked
āNineteenā, he said.
Nearby a guy in a Panini Express shirt told us he was working when his boss suddenly turned and ran without saying anything.
The next thing he saw was a traveler crawling behind the counter for shelter.
We waited on the bus for about ten minutes when an airport staffer boarded in the front and cheerfully, loudly gave us directions.
āAlright, hereās what weāre gonna doā, he projected.
āWeāre going to exit the front of the bus and follow [muffled muffled].
OK? Do you understand? Who understands?ā
He spoke with the cadence of a DJ trying to get the party started.
I had missed some of what he said, but I still felt kind of compelled to echo back, āI understand!ā
This was the clearest instructions I heard all night.
Give that guy a medal.
The bus was packed, and there was a second exit in the back.
A woman shouted out to the bus driver, āBack door!ā
The kind of thing you might shout on a city bus on a normal day, when the door hasnāt opened.
I couldnāt help but wonder if the front door was somehow safer than the back door, and that was why we were being told explicitly to exit through the front door.
Upon exiting I followed a stream of people back toward customs.
The crowd was much bigger now than before, and much calmer.
There were more police.
At some point a fire truck showed up.
People started to relax, breath, sit.
I noticed my dad has replied to me:
Dad (23:19, 5:19 in London):
Just got up to pee.
Any new updates?
News at 15 minutes ago says unconfirmed reports of gun shots at terminal 8 & 1 (yours)
I told him where I was and that it was much calmer now.
Dad:
Be patient & be a calming influence.
See if anyone is alone & nervous
Me:
Yep
I pictured my mom sleeping and my dad glued to his phone.
The Swedish woman approached me.
āHeyā, she said.
I was shocked and very relieved to see a familar face.
I had been traveling alone on my vacation and kind of reveling in the freedom to do whatever I wanted at any time.
But during this incident I wasnāt myself, wasnāt independent, I was just alone, an unindividuated animal in a suspicious herd.
We shared a water bottle she got from a fireman.
I started to feel like a human again.
She missed her transfer to Arkansas and was on the phone with her friend in New York to see if she could stay there.
Many people sat down.
I realized I felt safe enough to sit down.
Soon we started queueing toward customs and I felt safe getting in line.
A young woman stood with us for a while, seemingly wanting not to be alone.
We parted ways inside, and I went through customs.
I think it was quiet.
The kiosk was working, and I punched in that I wasnāt planning to declare any food, spices, or anything.
I was glad I held onto my backpack as I dug my passport out.
The young southern man from the bus was ahead of me in line.
āI found herā, he said, indicating his nineteen year old sister.
It took me a moment to register who he was and figure out what to say.
āIām really glad to see thatā, I finally said.
The police officer checked my passport and barely glanced at my customs slip.
āYouāre okayā, he said, and stamped my passport.
As I exited baggage claim, I was met by a huge group of people waiting for the long-overdue terminal 1 arrivals, and felt momentarily like they were all there just for me, just to tell me I had been brave and I could rest now.
I felt destabilized by how normal operations were on this side of the terminal, when it had been such fright and chaos on the tarmac.
There was no question I was taking a taxi.
I waited for a while and ended up sharing one with three other people.
The dispatcher was long gone, so the drivers were free to negotiate whatever prices they wanted.
No problem.
On the drive home, we compared notes.
A guy my age sat in the front seat, and a mother and teenaged daughter sat with me in the back.
The news was saying it was all a false alarm and that there was no evidence of a shooter or a bomb or anything.
The daughter said something about how scary the night had been for her, and her mother made the point, āWe were never actually in danger at any point.ā
When I eventually found my way to my bed (around 2:30) and closed my eyes, I felt waves of cold energy coursing through my limbs.
The fact that there had been, actually, nothing to panic about was an enormous relief, of course. But it made things all the more eerie the next morning, when we woke up feeling like survivors of a ghost trauma, a minor local-news story. For several hours, we were in the flood of panic and chaos of an ongoing act of terror. Thereās no other way to describe it. That it was an overreaction almost doesnāt matter; in fact, that is how terrorism works.
Reading it made me feel some amount of relieved and want to write something myself.
Using terminal text editors has a lot of advantages, but for a while the biggest disadvantage Iāve felt as a vim user is that itās kind of hard to interact with the system clipboard.
Iām aware that thereās a concept called āregistersā which are something like multiple clipboards that you can copy and paste from, and one of them is the system clipboard, and the others are all virtual, or something like this, but I havenāt taken the time to really learn how those work yet.
If I want to copy a helpful code snippet from Stack Overflow into vim and I copy it to the mac clipboard, and then press ācommand + vā to paste it into vim, the indentation gets totally screwed up.
This is becuse vim is trying to help.
It doesnāt know that I just pasted, it thinks that I was suddenly just typing super super fast and each newline character I ātypedā caused it to helpfully auto-indent the appropriate amount.
When I actually am typing, this is helpful.
But when Iām pasting, itās kind of annoying.
(You can see in this example that not only is the indentation screwed up, but also there is an extra end which vim-endwise helpfully tried to auto-insert)
The workaround Iāve used for a while is to always run :set paste before I paste, and then :set nopaste afterward.
This mode doesnāt auto-indent.
It also breaks a number of my other vim configurations, such as jk being an alias for the escape key.
Pretty annoying.
Copying text out of vim is even more difficult.
I can use my mouse to highlight the text I want to copy and then press ācommand + cā to copy it, but this is pretty awful, too, because itās very easy to accidentally copy things like line numbers (which are just text in the terminal, and your mouse doesnāt know to avoid it) or to even copy text from multiple files which you happen to have open side by side in split buffers, such that the code is totally broken when you paste it out again.
My workaround for this is even worse! I generally close my splits, turn off line numbers (:set nonumber) and sometimes make my font smaller so I can fit the whole lines on my screen and select the text and copy it.
When I do this, I generally pick up a bunch of trailing whitespace that wasnāt there in the source code.
It totally stinks.
Sometimes I will just open the file in Atom so I can copy text in a sane way.
Other times I will run :! cat % | pbcopy to āshell outā to a bash command and copy the entire contents of the file to the clipboard.1
OK.
So obviously that sucks, right?
Thatās just some context for how Iāve been doing things.
I meant to look into a better technique and never got to it.
The other day at work I saw my coworker Will very seamlessly copy some text out of vim and paste it into Slack.
Scandalized, I asked him how he had done that.
He told me heās using neovim and itās probably something neovim does.
I made a note to look into it.
Iām open to the idea of using neovim instead of regular vim ā I think itās cool that you can run a terminal inside vim, which makes me wonder if I even need tmuxā¦
One of the first things I found in my research was a neovim issue from April 2014 about how some vim configuration was working in vim but not neovim
ā¦ the follwing works perfectly fine with mainline vim, āyā and āpā work with X clipboard:
set clipboard=unnamedplus
but not for neovim.
Iāve tried setting it to:
set clipboard=unnamed
still works in vim, but not neovim.
Hm. Wait. Does this mean vim already supports clipboard integration this whole time and no one told me!?
Indeed, yes, and this is why Iām writing this blog post to tell you.
I feel like thereās a good chance you already knew.
So yep, I added that second config option to my .vimrc and now it works great:
I can yank text from vim and then ācommand + vā it into other apps.
I can copy text from Stack Overflow and then āpā it into vim ā no weird indentation behavior or anything
I may yet switch to neovim2 or learn about registers, but for now I donāt yet need to, and for that I celebrate.
The ! means to run a bash command; the % will expand to refer to the file name; pbcopy is a mac thing for piping data to your clipboard.Ā ↩
Iāve been interested in the Rust programming language for a while, but it wasnāt until this week that I wrote something in it which I found useful.
Letās rewind.
I like to have a random, nice emoji in my shell prompt.
Itās just to add a little flair to the proceedings, some color.
The emoji donāt mean anything, theyāre just for fun.
random_nice_emoji is a command line program on my PATH.
git_prompt is a shell function.
The \$(...) syntax means that the program or function should be called each time the prompt is drawn, not just once when you first open your terminal.
I could have written random_nice_emoji as a shell function if I could figure out how to use shell arays, but I could not.
But over time I noticed that it was kind ofā¦.. slow.
And I started to wonder if maybe my fun affectation was worth it.
Some benchmarking suggests that this program takes about a tenth of a second to run.
Thatās not a lot, really.
But we can do better.
Maybe the shell function would be much faster, but yea, still donāt know how to use shell arrays.
So letās try writing this little script as a Rust program ā Rust is supposed to be fast!
To make a new command line program in Rust, you can use Cargo to scaffold the project:
cargo new random_nice_emoji --bin
The --bin part means that it will be a command line program.
Without it, I think the idea is that youāre making a package which will be used in an application.
That command crates a directory called random_nice_emoji, and within that there is a file src/main.rs which is where you put your code which should run when the command line program is invoked.
Hereās what I came up with (Iām really new to Rust so this isnāt necessarily good code):
externcraterand;userand::distributions::{IndependentSample,Range};fnmain(){// cool, friendly emoji that look fine against a black terminal backgroundletlist=vec!["š","š ","šø","š","š","š","ā","š","š","š","āØ"];letbetween=Range::new(0,list.len());letmutrng=rand::thread_rng();letindex=between.ind_sample(&mutrng);letemoji=list[index];print!("{}",emoji);}
I couldnāt find a super-simple sample method, so I did my best to adapt the example from the docs for the rand crate to achieve that behavior.
You can install it yourself with cargo install random_nice_emoji.
Maybe I shouldnāt have released it because itās not generally useful ā but itās very convenient for me so I can install it on multiple computers, for example.
And this one usually finishes in 0.006 seconds ā 16 times faster.
And it was maybe 5 times harder to write?
Iām hopeful that if I get better at Rust, that will go down.
If youāre into Ruby and intrigured by Rust, I recommend checking out this Helix project which makes it easy to embed Rust code in Ruby projects to ease performance hot spots.
I havenāt used Helix yet, but that talk does a really great job of explaining the idea and was really inspiring to me.
One thing I like about Ruby is that you can use a little punctuation in your method names, which can help you write expressions that read like nice sentences:
delete_useruserunlessuser.special?
Kind of fun.
I knew a guy who liked to use these question mark methods in conjunction with the ternary operator to write code that reads like a panicked friend:
user.special??protect(user):delete(user)
The double question mark always makes me smile, which makes me wonderā¦
Can I just define a method with double question marks right in the method signature?
Like this:
classUserdefspecial??name=='Max'endend
Turns out: nope.
Thatās a syntax error.
Not valid Ruby code.
Wellā¦
OK.
But this is Ruby, so thereās not just one way to do a thing.
Thereās another way to define a methodā¦
Letās try this:
OK itās not as satisfying calling the methods with public_send, but as far as I know, itās the only syntactically-correct way to call these methods.
note: this is going to be sort of personal and self-indulgent and Iām mostly writing it for myself to work out some ideas and make some decisions
Iām writing this from vacation, in Mumbai.
Last year, I googled ābest vegetarian citiesā and Mumbai was near the top.
New York City, where I live, was also near the top.
Itās not a shock ā New York has many specialty restaurants that focus on vegetarians and vegans, and almost any restaurant has something for me.
But after spending a few days in Mumbai, I think itās truer here.
In software, we sometimes talk about āsensible defaultsā.
If youāre going to provide options to your user to change the behavior of your app, the default behavior should probably make sense for the majority of users.
I donāt think the majority of Mumbaikers are vegetarian, actually, but the nomenclature suggests it.
It manifests like this:
FourSquare tips like ābest place for non-veg in the cityā.
Restaurant servers asking āveg or non-veg?ā
Restaurant signs indicating that a place is āpure vegā (which I think means itās suited for Jain vegetarians)
I like that the ānonā is attached to āvegā and not āmeatā.
If you become a vegetarian, people will want to know why.
Iāve been a vegetarian for a little over three years, and I often struggle to come up with a good answer.
This dissatisfies people, myself included.
The truthful answer is that Iām a vegetarian today because I was a vegetarian yesterday and for no other conscious reason.
This of course raises a few questions:
In February 2013 my toe hurt.
I thought maybe it was broken.
I had a vague memory of stubbing it badly while walking in the snow.
There were drinks involved.
The doctor x-rayed me and said it looked fine.
No broken toe or anything.
āYou probably have goutā (I paraphrase).
Gout, as I understood it, is a form of arthritis.
If your diet is too purine-rich, uric acid causes crystallization in your joints, which can be painful or uncomfortable.
(This is probably not a fully accurate definition of gout ā Iām writing without WiFi currently and going from memory from a conversation 3 years ago)
He took some blood to assess the levels of uric acid and gave me a cheat sheet of foods to avoid.
He didnāt tell me to become vegetarian.
He told me to moderate my levels of purine by limiting my consumption of specific foods to lower levels.
The list was kind of surprising to me: I recall spinach and oatmeal being on the no-fly list.
There were specific amounts of red meat I was recommended to eat in a week, limited to a few ounces.
Similarly for other meat, maybe a little more generous.
Iāve never been a very conscientious eater.
I still donāt feel like I understand the basics of nutrition.
I wasnāt excited to memorize a list of foods to eat or to buy a kitchen scale.
I decided to try eating vegetarian for a few weeks and see if the toe pain went away.
It did.
Curiously, the blood test showed normal levels of uric acid.
I mightāve had it, anyway although I may never know.
I think in the first few weeks I was just superstitious and didnāt want the toe pain to return.
It was very inconvenient!
I could barely walk.
And then it became a habit and I forgot about stopping.
In the interim, Iāve bought a few books about veg* eating, but I think Iāve only finished one: Eat & Run.
Itās a very inspiring memoir about a vegan ultra-marathoner.
This dude runs 100+ miles at a time powered by smoothies, salads, and black bean burritos.
He makes a very persuasive case for veganism as an ideal diet for some kinds of athletic pursuits.
Iām not an athlete, but I do encounter people who insist that they ācould never be vegetarianā because their gym regimen requires amounts of protein which would be impossible, inconvenient, impractical, or unaffordable to attain through a plant-based diet.
Theyāre probably right, I donāt know their life.
One takeaway from the book I took away is that most Americans are consuming too much protein.
I like to share that when people worry about my protein.
People worry about my protein all the time.
āBut how do you get your protein?ā
People need to know.
Iāll tell ya: I donāt worry about it.
Iām still not a very conscientious eater, and I feel pretty much fine.
I think I feel a little better than before, but I donāt really remember.
(This post continues not to be medical advice.)
2. What do I like about eating vegetarian?
There are a few benefits Iāve picked up on, which Iāll enumerate now, as they occur to me.
Easier decision making
Some people talk about clothing this way: I wear the same thing every day so I have one fewer decision to make each day.
I havenāt heard people talk about food in the same way, but I think itās similar.
I have the personality where I feel compelled to read the whole menu before I make a decision, lest I make the mistake of overlooking something I might like.
Have you ever been to a diner?
These menus are an astonishment.
I can get thru a menu much quicker when I can skip all of the non-veg items.
No more āplease, come to me lastā; I know what Iām ordering.
No more storing and cooking meat
I used to try to cook meat.
I was real bad at it.
I couldnāt make a burger without setting off the smoke alarm or undercooking it.
I couldnāt defrost a chicken breast without accidentally cooking it a bit, which I found kind of gross at the time but pushed down.
I didnāt really enjoy handling raw meat ā itās kind of slimy and sticky, right?
I donāt really remember, and maybe itās grown more ghoulish with distance.
No more gristle, no more veins, no more bones
Itās been a long time since Iāve taken a bite and felt a surprising popping resistance in my mouth.
I used to secret unpleasant, gristly bites into napkins.
I used to worry I wasnāt effective at extracting as much meat as I could from a bone.
I used to avoid eating veins.
No more!
Physical comfort
Meat sits like a lump in your stomach in a way that vegetables donāt.
Restaurants sometimes serve these giant sandwiches, burgers, steaksā¦
And I would eat the whole thing, and it would just sit there.
Look, I donāt want to go into too much detail about gastro-intestinal scenarios.
But letās just say itās harder to cause problems when you skip all that stuff.
Moral correctness
This is a touchy one.
When a meat eater asks me why Iām vegetarian, what they really seem to mean is: do you think Iām an asshole?
I donāt think youāre an asshole.
But I do think itās morally correct to avoid eating meat.
I donāt think itās majorly evil.
But I think itās kind of wrong.
I donāt feel strongly enough to try and convince others to give up meat.
But I do take a small amount of pleasure in feeling like Iām doing the right thing, the same feeling I get when I recycle.
Thatās the moral level I put it at.
Itās a nice thing to do.
I ate meat for 24 years and didnāt eat meat for 3 years.
I think of it like Iām offsetting some damage, paying off some debt.
If I take that thought to its conclusion, I should remain vegetarian for another 21 years, after which point I would be in the black and could start eating meat again guilt free.
Thatās not necessarily the plan, by the way.
Having a label for my diet
There are many diets. Iāll list a few (summarized crudely):
Omnivore ā Iāll eat anything
Kosher/Halal ā Iāll eat anything except a few specific things
Vegetarian ā Iāll eat anything except an animal
Vegan ā Iāll eat anything unless an animal was involved
Jain vegetarianism ā Iāll eat anything except animals, eggs, and vegetables which grow in the ground
Before I stopped eating meat I didnāt belong in any of these categories and I was kind of embarrassed about it.
Not a deep burning shame or anything, but I had a hard time explaining it, and I was put into some uncomfortable situations.
My diet was something like: āInverse Pescatarian ā Iāll eat anything except seafoodā¦ or mushroomsā¦ or green olivesā¦ or solid tomatoesā¦ or a few other thingsā.
Not great!
Iām very proud and happy that I fit into a group now, called vegetarian.
People understand it and people have been mostly happy to accommodate what they can understand.
And, happily, Iāve expanded to fill the space I entered and have come to appreciate many or most of the vegetables I used to discriminate against.
If I were to start eating meat again, I think I would need to eat seafood as well, or I wouldnāt belong to a group anymore.
3. What do I do next?
What does it mean if youāre a vegetarian but every night you have vivid dreams of eating meat?