Open to line in vim from grep results

I often find myself doing greps thrughout different codebases to find variables that I want to change. For example:

Element.php:497:            case \ast\flags\UNARY_BOOL_NOT:
Element.php:727:            case \ast\flags\UNARY_BOOL_NOT:

These results are sometimes buried in large files, and it's a pain to open them up in vim and have to search again for the variable I want to change. Wouldn't it be great if I could just use vim to open the grep formatted file:line format? Well, you can! Check it out.

fileline.gif

Here's how to get this set up. First, since I mostly find myself using git-grep these days I needed to enable line numbers in my .gitconfig. You can do that with a config stanza:

[grep]
    linenumber = true

Next you'll want to install the file:line vim plugin. Install using your preferred method, there's nothing fancy here.

Now you're done! Enjoy opening grep results in vim and jumping directly to the correct line. Thanks to Chuck Ha for pointing me to this originally.

Comparing the PHP 7 and Hack Type Systems

One of the exciting things about PHP 7, aside from the incredible performance improvements, is the introduction of scalar type hinting coupled with an optional "strict" mode. When reading the RFC I noticed that PHP 7 code written with type hinting begins to look a lot like Hack. I wanted to find out if you could execute the same code in PHP 7 and Hack, and what the differences in execution might be. Here's what I found out.

The Setup

Just to get this out of the way:

$ php --version
PHP 7.0.0-dev (cli) (built: Apr 23 2015 01:12:36) (DEBUG)
Copyright (c) 1997-2015 The PHP Group
Zend Engine v3.0.0-dev, Copyright (c) 1998-2015 Zend Technologies
with Zend OPcache v7.0.6-dev, Copyright (c) 1999-2015, by Zend     Technologies


$ hhvm --version
HipHop VM 3.8.0-dev (rel)
Compiler: heads/master-0-gd71bec94dedc8ca2e722f5619f565a06ef587efc
Repo schema: fa9b8305f616ca35f368f3c24ed30d00563544d1

In order to execute the PHP code in HHVM without modifying the opening tags in the source code files I had to execute hhvm with the -vEval.EnableHipHopSyntax=true flag set.

Some Examples

Let's look at a simple example.

Executing this in PHP 7 returns:

Fatal error: Argument 1 passed to myLog() must be of the type string, integer given, called in /home/vagrant/basic/main.php on line 9 and defined in /home/vagrant/basic/main.php on line 4

Looks good! PHP 7 is correctly telling us that we're passing an integer ($a + $b) into a function that is expecting a string and throws an appropiate error. Let's see what HHVM says:

Catchable fatal error: Argument 1 passed to myLog() must be an instance of string, int given in /home/vagrant/basic/main.php on line 6

There are a couple differences evident here:

  • HHVM calls this a "catchable" fatal error. This is interesting as in the RFC the error shown actually matches HHVM's error.
  • HHVM says the error occurred on line 6 where PHP says it occurred on line 9. I prefer HHVM's approach here as it shows us where we called the function with the bad data, not where the function is defined that we are calling with bad data. UPDATE: I was confused, PHP 7 is the one telling us more information here. I always like more information with my errors. :) Thanks commenters! Here's another example that illustrates an important difference between PHP 7 and Hack.

When executed in PHP this function happily executes. When executed in Hack we get this type error:

/home/vagrant/nullable/main.php:4:16,21: Please add a ?, this argument can be null (Typing[4065])

Hack doesn't allow default arguments with a value of null as it "conflates the concept of an optional argument with that of a required argument that allows a placeholder value" (See O'Reilly's new book Hack and HHVM). Instead, Hack recommends that you make such an argument nullable in addition to providing the default value, like so:

Let's try something a bit more complicated. What happens if we mix strict and non-strict files in PHP? Note that defining strict mode at the top of the file has no effect in HHVM.

logger.php is defined as being in strict mode, yet PHP allows us to pass an int into it from a non-strict mode file. HHVM throws an exception in the same scenario. What happens if we make add.php strict?

Fatal error: Argument 1 passed to myLog() must be of the type string, integer given, called in /home/vagrant/separate_files_mixed/add.php on line 5 and defined in /home/vagrant/separate_files_mixed/logger.php on line 4

That's better. So it looks like functions defined in a strict file are only strictly type checked if the calling code is also defined in a strict file. On the flip side, what happens if we call a non-strict function that is type annotated from a strict function? To test this I changed logger.php to be non-strict and made add.php strict:

Fatal error: Argument 1 passed to myLog() must be of the type string, integer given, called in /home/vagrant/separate_files_mixed/add.php on line 5 and defined in /home/vagrant/separate_files_mixed/logger.php on line 3

So it appears that functions are only strictly type checked if they are called from a function that is defined in a file declared as strict. However, this only affects direct child calls of the file declared as strict. If we declare main.php strict, PHP happily returns 4 despite the mismatched type we are passing into log().

In Hack this relationship is reversed. If HHVM executes main.php in non-strict mode, and logger is written in Hack (with a hh tag at the top of the file) we still get a type error despite the fact that the file making the call is not written in Hack.

Catchable fatal error: Argument 1 passed to myLog() must be an instance of string, int given in /home/vagrant/separate_files_mixed/logger.php on line 5

Another interesting difference between Hack and PHP's type system comes from PHP's handling of the float annotation. Take this code example:

When executed in PHP this returns '3' even though we are passing ints where we have annotated a float, and despite the fact that strict mode is enabled. The reason for this is that widening primative conversion is supported in PHP 7's strict mode. This means that parameters annotated as float can accept an int as (almost) any int can be safely converted to a float. HHVM does not support this and will throw a type error when the above code is executed:

Catchable fatal error: Argument 1 passed to add() must be an instance of float, int given in /home/vagrant/main.php on line 6

If there are any other big differences I've missed, or other scenarios I should enumerate here, please let me know in the comments. I would love to keep exploring!

Wrapping It Up

While there are many features in Hack that PHP 7 does not support (nullable, mixed types, void return types, collections, async, etc) I am excited by the safety and readibility PHP 7's new strict mode enables.

After writing a couple small programs in Hack I've realized that it's not types themselves that make writing Hack enjoyable: it's the tight feedback loop Hack creates between the machine and myself. Integrating the Hack type checker into my editor means that my entire codebase is analyzed in a split second as soon as I save a file. This immediately surfaces any dumb, or subtle mistakes I made. I find myself writing code fearlessly: when I forget what a function returns, I just write code that calls it with what I think it returns. If I'm wrong, the type checker will tell me immediately. I can fix it quickly, and move on.

PHP has always facilitated a tight feedback loop between the machine and the developer. Save the file, reload the browser, repeat. Hack's type checker makes this even faster. I look forward to being able to build similar tooling on top of PHP 7's strict mode.

Anyone at Etsy Can Push Code. Here's Why

About a month ago I published a blog post on Etsy's Code as Craft blog detailing the company's Engineering Rotation program. I did not expect it to reach as many people as it did.

I remain humbled by all the feedback I've received from people all over the world.

"It says a lot about the management of Etsy that they encourage designers and product managers to do a rotation on the coding side, when I wasn't able to convince my team leaders to let php developers from one project rotate to work on another."
"That is just the coolest idea ever. For non-engineers, software can be a sort of black box filled with "code," whatever that means. This knowledge gap frequently leads to conflicts when engineers take longer to build a feature than non-engineers would like, or when things break that just seem so simple. Getting everybody involved in the deliberate, painstaking process of writing quality software is a fantastic way to ensure the everybody is on-board with the way code is written and minimizes interdepartmental friction. Kudos to Etsy!"
"Great idea. I'd love to see a writeup about a rotation in the other direction, ie give engineers a taste of the business side of the house. As a data scientist I speak a lot with Sales and Engineering and sometimes the two teams seem worlds apart..."
"I loved everything about this article."

As a result of this tremendous response I got the opportunity to speak with folks doing or trying to do similar programs at their own companies. I've learned a lot from these conversations. First, there is a large demand from people in the technology sector to learn about what their colleagues are doing.

"Just as it’s valuable for designers to more deeply understand the craft of engineering, it seems like it would also be valuable for engineers to understand the craft of design! Or product management…"

Second, I have talked to several people in leadership roles at their companies. To them rotations aren't just fun and games. They are looking to them to solve serious problems in their business. What starts as a cultural rift between two departments can quickly result in employee turnover and a breakdown in communication.

Laravel on HHVM

Intrigued by the HHVM team’s claim that Laravel’s test suite passed 100% when run on HHVM, I decided to get a basic Laravel application running on HHVM.

What is HHVM?

First a history, lifted from The Great Book of the Internet:

In the beginning PHP was not a programming language, but a set of CGI Perl scripts used to maintain Rasmus’ personal homepage. One thing lead to another and eventually the core PHP interpreter was rewritten and called the Zend Engine. If, like me, you’ve always wondered what “Zend” means, now you know.

A bunch of websites are now written in PHP. One you might have heard of is Facebook. And Facebook, being one of the biggest websites in the world, had a problem: how can we take all this PHP code that we have, and make it as fast as possible?

The programmer in you should be jumping up and down saying “I know! I know! Compile it to C(++)!” That is exactly what Facebook did with a project they called HipHop for PHP, or HPHP for short. Using the HPHP compiler Facebook could compile all their PHP code in to a binary, ship it off to their servers, and massively increase their performance. In fact, Facebook realized up to 6x the speed of Zend PHP. Awesome!

Unfortunately the “ship it off to their servers” part wasn’t too awesome. The compiled binary exceeded 1GB. Even worse, maintaining the HPHP compiler as well as the needed HPHPi (development environment) and HPHPd (debugging environment) was a significant undertaking. Perhaps the worst problem was that HPHPc, being a compiler for an interpreted language, could not support some of the features of PHP such as eval() and create_function().

To get around this Facebook deprecated HPHPc and created a PHP virtual machine called HHVM. HHVM converts PHP code into machine readable bytecode, similarly to the JVM. This bytecode is then translated into x64 machine code at runtime using a just-in-time (JIT) compiler. Now Facebook doesn’t have a lengthy build step, and can ship only changed files to their servers on deploy instead of a 1GB binary, while retaining the performance advantage of HPHPc.

HOW DO

Sweet! Let’s run Laravel on it.

I first installed HHVM on my OS X 10.9 Macbook Air, but it didn’t seem to work quite right. When I tried to access the server over HTTP it would peg the CPU and just sit there.

Then I installed HHVM on my Ubuntu 13.10 x64 server, using the instructions on the HHVM wiki which worked beautifully. After that I ended up with the hhvm binary located here:

~/dev/hhvm/hphp/hhvm/hhvm

A clunky directory hierarchy, but whatever. Feel free to symlink it in to /usr/local/bin if you want to make it easier to acccess.

Now comes the Laravel specific sauce. Taylor Otwell posted the config that he has used on Twitter so I used that. Unfortunately, laravel pastebin is down at time of writing so I have mirrored it as a gist.

wget that down into your home directory: (apologies for the terrible formatting, not sure what is wrong here)

~$ wget https://gist.github.com/jazzdan/8262454/raw/5d190c4de5252399cb421f344a789aeb56bb4ebd/config.hdf

Now let us get Laravel installed.

Install composer if you haven’t already:

~$ curl -sS https://getcomposer.org/installer | php
~$ sudo mv composer.phpar /usr/local/bin/composer
~$ sudo apt-get install php5-mcrypt

Check to make sure mcrypt is there now.

php -m | grep mcrypt

Install laravel:

~$ composer create-project laravel/laravel hhvm-test --prefer-dist
:$ cd hhvm-test
~$ composer install

Once that has completed you should be able to run Laravel on HHVM with this command:

~$ cd ~/dev/hhvm/hphp/hhvm
:$ sudo ./hhvm -m server -c~/config.hdf
mapping self...
mapping self took 0'00" (214686 us) walltime
loading static content...
searching all files under source root.source..
analyzing 5 files under source root...
..loaded 25 bytes of txt firstles
loaded 25 bytes of static content in total
loading static content took 0'00" (15735 us) wall time
page server started
all servers started

If you see output that looks like that, then you should be good good to go!

I have stepped through all of the Laravel Quickstart on HHVM and everything appears to work, including MySQL database access. I’ll report back as I progress in to actually developing a Laravel app on it.

Many eyes make for shallow bugs, or so I’m told. Please try this out on your more developed Laravel projects and report relevant bugs to the Laravel and HHVM teams. I envision a future in which HHVM enables everyone to have more performant, more easily deployed PHP applications.