`isNotEmpty` on Array

I know reasoning by analogy is dangerous, but let's discuss the in/not in Python operators, and the contains(_:) Swift method.

Let's say we implement an algorithm read in a book, which contains this sentence:

If the node has already been visited, ...

If our language is Swift, we may write:

if visited.contains(node) {

In Python, however:

if node in visited:

How could both languages provide such different wordings for the same test, considering both have the same constraints: the actual algorithm that tests for inclusion depends on the type of the container. Both in and contains are polymorphic.

This polymorphism is totally assumed in Swift: contains(_:) is declared on Sequence, with more or less private ways for concrete types to provide an efficient implementation. Swift generally wants us to know how methods are dispatched across protocols, classes, structs, etc. This knowledge allows us to write good/fast/maintainable/testable swift code. To put it more mildly, whenever a developer learns about Swift dispatch, this dispatch is clearly visible in the code: contains is a method on the container because containment test depends on the container. The subject is the container because this is how the language works: if visited.contains(node)

However, Python hides this polymorphism behind the __contains__ magic method, documented under a chapter called Emulating container types. This magic method provides the same level of polymorphism which is required for an efficient implementation. But this polymorphism is not visible in the code, because knowledge about polymorphism (and magic methods) is not necessary to use Python, a scripting language. The Python code does not show what is happening, because the language has rather follow natural language. The element is the subject of the containment test, as in English: if node in visited.


Swift requires a more abstract mind than Python.

Swift: if you understand why containement test is a method on the container, then it is likely you'll also understand why there is an independant ! negation operator, and you won't have problem chaining them:

if !visited.contains(node) { ... }

Python: if we provide English-like in operator for containment test, then we'd rather also provide the not in negated operator in order to avoid confusing explanations about expressions, operator precedence, parenthesis, etc:

if node not in visited:

The moral of this story is that Swift has already picked his side. And it is not Python's. Extra apis that help the language get closer to English are not very warmly welcomed, because the language is not grounded on English: it is grounded on the visibility of dispatch. What you see is what is happening.

On a side note, I'm happy I wrote this, because it is an interesting way to answer the "Prefer method and function names that make use sites form grammatical English phrases" mantra of the API Guidelines. Some English sentences will have to be twisted in Swift, because efficient dispatch is more important than the structure of the equivalent English sentence.


EDIT: this is not a hard rule, of course :-) We're discussing about having both isOdd and isEven right now. It looks like those trivial methods will be easily accepted (they're not that trivial, actually). Bool.toggle() had a more contrasted reception. I enjoy reading "little" pitches like isNotEmpty, because they spread the language culture, and influence it in the same time. This is a virtuous feedback loop.

And the list of commonly rejected changes is short.

7 Likes