HNHacker News
TopNewBestAskShowJobs

ambivalence

848 karma · joined April 30, 2009

Łukasz Langa. Python guy at Meta. Previously, CPython Developer in Residence. Python 3.8 and 3.9 release manager. Creator of Black, an opinionated code formatter.

Contact information in the KeyBase link below.

[ my public key: https://keybase.io/ambv; my proof: https://keybase.io/ambv/sigs/YFlWGlv21O-p2KBCGkahQq5QvzaW2fYVzzXGYMEreM8 ]

$2a$11$70w6J.UbVsGwuTMIvSTq5Oh97csRvkT9bz2BuWASdYI1W4MhnMDU2

submissionscomments
ambivalence··on Black: An uncompromising Python code formatter
For a large codebase that uses Black, you might want to look at PyPA/Warehouse or Fabric 2.
ambivalence··on Black: An uncompromising Python code formatter
Originally PEP 8 had 79 characters. Now that was a weird choice so most companies went with 80 instead, including Facebook. You want a low-ish limit because it makes it possible to fit two files side by side on a typical screen resolution. Even if you don't edit like that, you look at diffs like that. More importantly, a low column limit is helpful to disabled engineers who don't have to navigate horizontally so much.

So we used 80. I always felt bad when the linter stopped people from pushing impactful changes because they went over the limit by two characters. So two years ago I set up a "highway speed limit" style warning in flake8 (code B950 in PyCQA/flake8-bugbear). What it does is it keeps your limit intact (for example "80") but doesn't trigger unless you went over by more than 10%. So the limit happens to be 88.

When I was working on Black, I was faced with a dilemma. Should the formatter stick to 80 or be able to "go over" a bit, too, as we would let humans do. I felt like the latter made more sense as the resulting code looks nicer (fewer occasions to break a single line into three or more). Then I remembered Raymond's talk "Beyond PEP8" where he mentions that experience shows "90-ish" is the wisest choice. So I went with it.

ambivalence··on Black: An uncompromising Python code formatter
What don't you like about the exceptions? The code and the documentation would both be simpler without them. They are there because the end result is closer to what a human would do in those situations.

And the two exceptions you mentioned are ones you will also have to make if you want to stay PEP 8 compliant (pycodestyle's E203 is invalid inside slices) and you want your code to execute on Python pre-3.6 (where you can't add trailing commas to calls and signatures containing args and *kwargs).

ambivalence··on Black: An uncompromising Python code formatter
Yeah, I wasn't willing to die on that hill, especially that I'm introducing a new default value that wasn't popular before.
ambivalence··on Black: An uncompromising Python code formatter
Black is a simple tool. It tries to implement a single code style well. It's not configurable.

We tried YAPF before and could never roll it out for everybody. I even contributed the "facebook" style to the tool. There were a few reasons why YAPF didn't work out for us but the most important were:

- YAPF would at times not produce deterministic formatting (formatting the same file the second time with no changes in between would create a different formatting); Black treats this as a bug;

- YAPF would not format all files that use the latest Python 3.6 features (we have a lot of f-strings, there's cases of async generators, complex unpacking in collections and function calls, and so on); Black solves that;

- YAPF is based on a sophisticated algorithm that unwinds the line and applies "penalty points" for things that the user configured they don't like to see. With a bit of dynamic programming magic it arrives at a formatting with the minimal penalty value. This works fine most of the time. When it doesn't, and surprised people ask you to explain, you don't really know why. You might be able to suggest changing the penalty point value of a particular decision from, say, 47 to 48. It might help with this particular situation... but break five others in different places of the codebase.

ambivalence··on Pyre: Fast Type Checking for Python
That shouldn't be hard to integrate. At Facebook we have it integrated with Buck which is pretty similar to Bazel.
ambivalence··on Pyre: Fast Type Checking for Python
No.

Supporting an entire new AST and type system (pattern matching) is a large investment. It can be made if there's enough of a userbase out there to justify it. That doesn't seem to be the case. Not yet at least.

ambivalence··on Python 3.7: Introducing Data Classes
Judging from your confrontational tone I will probably regret commenting but here goes.

Arguments accepted in __init__() are not necessarily tied to the so-called "shape of the type" at runtime. Fields with init=False, and the presence of ClassVar and InitVar is just two examples.

In terms of types of arguments passed to __init__(), they totally can be incompatible with the runtime type of the given field. There's nothing wrong with that. On the contrary, that is a useful feature. The obvious example is factories for field defaults. E.g. you can't store a list instance as a default value, it would be reused across your type's instances. Instead, you use default_factory=list. But when you do, what type does the respective argument to __init__ accept? Well, it's Union[YourType, MISSING] because you can omit it and it will initialize your type for you.

Type conversion is another common example. Your __init__ might accept timestamps as strings but always convert them to datetimes. Maybe you accept Unicode strings but internally store as bytes or vice versa? Maybe you support an external API so you have to accept a bunch of arguments that you later convert to a saner internal state? There are numerous use cases.

Summing up, don't confuse the signature of __init__ with the type shape.

ambivalence··on Advantages of monolithic version control
You don't ever push straight to the repo. You enqueue your changeset to be pushed by a central system. At Facebook we call this "asynchronous landing" and you're right, before this became a thing about five years back, at certain times of day it was very tricky to push your changes out.

Once you switch to this model, you can do convenient things like landing straight from the review system (by a "Ship it" button), landing after some checks were successfully performed, and so on.

Incidentally, this is similar to how merging pull requests by rebasing works on GitHub.

ambivalence··on Cape Town could be the first city to run out of water
Saying it's "ironic" would be somewhat harsh (but would still get the point across), saying it's "amusing" is just cruel. You know there's real people affected and the ones hurt will likely not be the ones responsible, right?

A bit of empathy would go a long way.

ambivalence··on The MacBook Air: A Decade’s Worth of Legacy
Doesn't it have the same butterfly keyboard as the new Macbook Pro?
ambivalence··on Open-sourcing MonkeyType – Let your Python code type-hint itself
Since this is how gradual typing works, the goal is to annotate every last function.

Good question about abstract base classes! Paraphrasing a well known cliché: types in functions should be forgiving in arguments (what the function accepts) and strict in return values (what the function emits). In our case, the human reviewer needs to decide if the argument types collected by MonkeyType should be generalized. In fact, the collected types might not even work in all cases and the type checker might complain. It's because annotations describe "what should be" whereas MonkeyType finds "what is". This is why a system like MonkeyType shouldn't even attempt to use abstract base classes in place of concrete types that it collected.

ambivalence··on Open-sourcing MonkeyType – Let your Python code type-hint itself
I'm not quite sure what you mean. Python has an external static checker for types, it's called mypy.

Python's type annotations are in fact very similar to Flow and Hack in the sense that they provide gradual typing. The specification (see: PEP 484) describes that only annotated functions are type checked. Calls to non-annotated code are treated as accepting any type in arguments and returning the Any type (a special type which effectively silences the type checker).

This generates a chicken and egg problem: if you don't have enough functions annotated, the type checker won't be able to provide meaningful output to you. So convincing people to annotate their code is harder: they don't see the benefit right away. Worse yet, you already have tens of thousands of functions in your code that you know work in production but were written before type annotations were introduced. It's not really feasible to come back and fill this information manually.

MonkeyType is a tool that gathers types at runtime and enables putting them back in your code as annotations. The goal is for mypy to have more information to work with, making it way more useful.

ambivalence··on Open-sourcing MonkeyType – Let your Python code type-hint itself
The idea to gather types at runtime is as old as PEP 484. The Dropbox and Facebook teams working on Python type checking know each other. We both worked on our implementations independently since we wanted to first test internally whether the idea holds water. For example, I personally thought it wouldn't be as useful in practice as it turned out to be!

We knew we're going to open-source each others' implementations, esp. that Instagram's is focusing solely on Python 3 which isn't useful for Dropbox at the moment. It just took a while to get through the process of open sourcing what we had (cleaning up the early implementation with limited documentation, decoupling from internal data stores, etc.).

Would it be cheaper if this started out in the open? Probably, but I don't think by quite the margin as you expect.

ambivalence··on Open-sourcing MonkeyType – Let your Python code type-hint itself
MonkeyType is Python 3-centric, PyAnnotate is Python 2-centric.

PyAnnotate couples re-applying the types with the tool, and uses type comments for this.

MonkeyType generates .pyi files that you can either use directly or re-apply them to your code as proper type annotations.

Other than that, MonkeyType is used on a daily basis internally and solves a bunch of common annoyances of systems like these, like duplicates in unions, applying better types to stuff that was already hand-annotated with Any, etc.

ambivalence··on Most popular Python packages now support Python 3
Yes.
ambivalence··on Most popular Python packages now support Python 3
I work at FB.
ambivalence··on Most popular Python packages now support Python 3
Facebook's WWW is Hack. Instagram's WWW is Django on Python 3.6.
ambivalence··on Most popular Python packages now support Python 3
New code at Facebook does use both. Instagram uses both extensively.
ambivalence··on Sean Parker unloads on Facebook “exploiting” human psychology
> Not sure how accurate it is, but the way Facebook's founding ideas are portrayed in The Social Network definitely screams "exploiting human psychology".

It's fiction. Yes, inspired by a true story but fiction nonetheless.

You wouldn't base your knowledge about Nikola Tesla on "The Prestige", would you?

ambivalence··on First field report of iPhone X
If you're using Apple CarPlay, don't upgrade (yet?). On iOS 11 it cannot even keep up playing music without glitches. Crashed twice on me when receiving a phone call. Never had those issues on iOS 10.3.

Rebooting helps. Feels like trying to use Windows on a cheap desktop to watch an HD movie in 2001.

ambivalence··on Bay Area hammered by loss of jobs: Lack of affordable housing strangles hiring
This is happening but, unlike software, cannot be bootstrapped by a few hackathons.

Just one example: http://www.businessinsider.com/facebook-housing-menlo-park-2...

ambivalence··on Introducing Atom-IDE
Well, I am editing remote code over SSH with Atom and Nuclide right now. It's been possible for a long time. Now you can even run a remote debugger on your Python program.
ambivalence··on What Nassim Taleb can teach us
> At one point he was planning to publish a book of his own aphorisms, as quoted by himself, while he is still alive.

He did, it's called "The Bed of Procrustes". I quite enjoyed it, there's quite a few brilliant thoughts there, even though they're sprinkled between countless cheap shots against his enemies.

ambivalence··on Ask HN: What laptop do you use?
I use two 13" Macbook Airs. One is an 1.3 GHz i5 from 2013 which is admittedly slowish at times with heavy Atom and browser use. The other is an 2.2 GHz i7 from 2015 and that one is pretty awesome.

The batteries on those machines are amazing. They really last for 7-9 hours depending on use. The 2013 one is starting to show the "Service battery" warning every now and then but no performance degradation is noticeable yet. It's been through 380 cycles so far.

If you use a non-Retina Macbook like those, I suggest using a bitmap font for programming (I'm using Terminus myself). It's totally sharp and easy on the eyes. Crank up the contrast in your editor's color theme and you're all set.

ambivalence··on How I discovered my left AirPod was bad
Report the Bluetooth problem at the Subaru service. When my wife drives back from work, our '15 Forester pairs with my phone on the kitchen table as soon as my wife stops the car in front of the house. Easily 15 feet and there's walls and the car's chassis between us.

This is pretty hilarious by the way because if the phone just about pairs and she turns the car off, iPhone keeps playing the music, just switching to the internal speaker. We have a running joke about her "walk-in theme playing".

ambivalence··on Python moved to GitHub
I know you're joking but just for the record: this process was started in late 2015, it's a surprisingly complicated endeavour to switch source control hosting.
ambivalence··on Torsimany: translate any JSON file to stylish, human-readable Markdown
Is there something wrong with how GitHub renders the Markdown you generate? The two examples given in the repo are not exactly human-readable and apart from bullet points I didn't notice any styling.
ambivalence··on Dismissing Python Garbage Collection at Instagram
PEP 442 describes the situation with good detail, including how it was in Python 2 and how Python 3 improves on it:

https://www.python.org/dev/peps/pep-0442/

ambivalence··on Dismissing Python Garbage Collection at Instagram
In fact, this is now fixed in Python 3.6. When gc is disabled by the user, the final collection is not done.

The effect is faster shutdown with less "copy on read" but some __del__ methods and finally: blocks in some generators might never get called.

← PreviousPage 3 of 4Next →