kmarekspartz

Expanding our capacity to respond to unforeseen changes

A comparison of imports in Python, Haskell, and Swift


At the last HaskellMN meetup, Danny Gratzer had a question about Python imports. Specifically, he wanted to import and re-export a constant. Here's how it is done in Python:

# a.py:
some_constant = 3.14

# b.py:
from a import some_constant

# c.py:
from b import some_constant

Edit: He had a follow-up question.

This reminded me that I wanted to compare the import styles of Python, Haskell, and Swift. Their imports are similar, though there are a few differences to keep in mind.

Python

Python has a few import styles:

import module1
from module2 import a, b, c
from module3 import *

The first loads module1 and brings it into scope. The second loads objects a, b, and c from module2 and brings them into scope. The third loads every object from module3 and brings them into scope.

The first is useful for short names (os, sys), but with module hierarchies it can be annoying. The second is my preferred style, as it forces you to name what will be used. The third is frowned upon, as you can accidentally overwrite variables if a module you import later provides an object with the same name as one you import earlier. Additionally, providing a list of what is going to be used in the file is useful from a documentation standpoint. “Explicit is better than implicit.”

Python modules are isomorphic to files. A module is either a file with that name or a folder with an __init__.py file in it[^1]. Submodules can be placed in the folder.

[^1]: A folder with an __init__.py is technically a package.

Python imports can be qualified using as:

from module import a as b

This imports a from module, but gives it the name b in scope.

Python imports can also happen anywhere in a file, even inside functions. This is a double-edged sword, useful for both making and breaking circular dependencies.

Haskell

Haskell, too, has a few import styles.

import qualified Module1
import Module2 (a, b, c)
import Module3

The first loads Module1 and brings it into scope. The second loads objects a, b, and c from Module2 and brings them into scope. The third loads every (exported) object from Module3 and brings them into scope.

These correspond loosely to the three Python examples, however, I put them in the roughly similar semantic order, rather than by ordering them by their similar syntax. Again, I prefer the middle one for similar reasons.

There is also a hiding option, which is the inverse of of the second option option above:

import Module hiding (a, b, c)

Haskell modules are made explicit within files:

module Module where
    ...

The convention is to put them in the corresponding file structure, though this is not enforced programmatically.

Unlike Python imports, Haskell imports need to be at the top of a file, optionally following a module declaration.

Haskell provides the as option, too, though only for module-level imports:

import Module as M
import qualified Module as M

However, the first example here also imports everything from Module in addition to qualifying the module-level import as M.

This would import everything from Module except a, b, and c.

Swift

Swift imports are not as diverse. They only provide equivalents for the second and third examples from above:

import var module2.a
import module3

The first loads module2 and brings it into scope. The second loads objects a from module3 and brings it into scope. There doesn't seem to be an equivalent to the module1 example from Python and Haskell.

Compared to the module2 examples from Python and Haskell, the example here provides two additional constraints. First, the import kind needs to be specified. In the example I gave here the import kind is var, though it could also be typealias, struct, class, enum, protocol, or func. The other constraint is each import from a module would need to be in its own line. A more precise equivalent to the Python and Haskell examples for would be:

import var module.a
import var module.b
import var module.c

This is a little excessive. I think a better syntax would be something like one of these:

from module import var a, var b, var c
import module (var a, var b, var c)

Like Python, Swift imports can be placed anywhere within a file.

The morality of import styles

Importing a module name is fine, though it can make some code hard to read due to the repetitive and verbose nature of including the module name for each access into the module.

Importing specific items from a module is my preferred import style, except when it isn't idiomatic (e.g. import sys in Python).

Importing everything from a module without naming each item is frowned upon because it doesn't convey everything to readers of the code. Code readers like to be able to see what is in scope in order to get a feel for what kind of code will be read in a file.

Additionally, if multiple modules define items with the same name, it is possible to overwrite imports implicitly, without notifying the reader:

# a.py:
x = 1

# b.py:
x = 2

# c.py:
from a import *
from b import *
print(x)

These suggestions are reflected in Python's PEP 8 and the HaskellWiki page on “Import[ing] modules properly”. These discuss the merits of the various import styles, and they arrive at similar conclusions, though the HaskellWiki page is less axiomatic and provides more rationale for the various decisions. There is not yet a similar document for Swift, though the official blog post on Files and Initialization mentions that you “can even import modules at the bottom of the file (although that is not recommended Swift style.”

Adjusting my metrics to better reflect my goals.


A case of accidental prioritization.

In January, I started using Beeminder to track my blogging. For each post, I've been adding a data point with a value of one, with a goal pace of about four posts per week. However, because each post had the same value, I had inadvertently set my sights for quantity over quality. If it doesn't matter how well I write, quality suffers at the expense of quantity[^2].

[^2]: Once I realized I was doing this, both quantity and quality plummeted.

In order to get around this, I should change what is being measured. Naively, I could change my goal to be N words per week (where N is initially my historic rate), but this would result in a different accidental prioritization of quantity over quality: I would write longer posts, not necessarily better posts.

Instead, I'm developing a quality measurement using natural language processing, and incorporating it into mindfeed. I'm unsure how exactly to calculate quality, so instead of guessing, I'm developing a set of features each of which I'll mind[^1] with Beeminder separately. I'll then manually rate my previous posts and develop a model which can assign a rating to a post using the features. Eventually, I may ask some prototypical readers to rate my posts. I could then develop a model for each set of ratings.

[^1]: mind, verb: to track data with Beeminder.

One feature will be length, thought as mentioned above, it cannot be used on its own. I'll also look at vocabulary diversity using the count of types as well as an information-theoretic approach. I will also be tracking readability measures such as the Flesch–Kincaid index. Another aspect to consider is uniqueness relative to previous posts. This can be simple, such as how many new words were introduced in this blog post, or more complex, such as vector-space distance.

Measurements are important, as they do change behavior, but what we measure can sometimes have unintended consequences. Choose your metrics carefully.

Swift has improved the syntax for its Array type.


I keep forgetting to mention that Apple has fixed one of the issues I had with Swift. In Beta 3, the syntax for Array at the type level has changed from String[] to [String], which corresponds better to the value-level syntax for Arrays. Credit to ThriftySwift.

Edit: I should also link to Apple's blog post announcing the changes.

Danny Gratzer has been reviewing packages on Hackage.


Danny Gratzer, the organizer of HaskellMN, has been reviewing packages from Hackage to demonstrate his approach to understanding new code. So far he's reviewed logict, a logic programming monad, and extensible-effects, an alternative to the monad-transformer approach. They're good reads even if you don't know any Haskell, as he describes how he traverses files in a code base using find and grep.

Ron Garret discusses some additional issues with LinkedIn


LinkedIn was actually asking me, not for my LinkedIn password, but for my email password. At the risk of stating what should be obvious, you should NEVER EVER give your email password to ANYONE. Anyone who has your email password owns you.

Ron Garret, Wow, LinkedIn [h]as gone seriously evil

Previously: Unbundling LinkedIn

Edit (June 2017): I caved and recently created a LinkedIn profile.

A friend of mine is working on an understandable regular expression implementation.


Andrew Clarkson is working on a pure Python implementation of regular expressions, with the intent to use it in a lexer for compiler implementation. One of his goals is to make it understandable and clear, one thing that doesn't often happen with regular expression implementations.

I'm looking for a good email client


I've been trying out email clients for a while now and I've not been too happy with any. I'm looking for something that gives me the following:

  • Multiple accounts with a unified inbox
  • Gmail-style threading (time-sorted and flattened)
  • Fast (both to receive messages and for user interactions)
  • Stable

What I've tried:

What I'm currently using:

  • offlineimap for archiving / backup
  • mu for command-line search
  • Mail Pilot for composition and organization
  • Gmail on iOS
  • Triage for checking non-Gmail accounts and sorting (archive/keep) large amounts of email.

Mail Pilot's scheduling features are nice, but it is very buggy and slow. Additionally, the clever foldering it uses makes it difficult to use with other email clients.

If I had an email client that did the above, but also seamlessly incorporated RSS/Atom feed reading, XMPP chat, and SMS I'd be elated. Maybe I should go back to emacs...

Tom Christie gave a guide on uploading to PyPI


Yesterday, my co-worker, Tom Christie, posted a guide on uploading Python modules to PyPI. I've done this a few times, but haven't had to deal with a package as complicated as the one he was uploading, since the packages I've uploaded are pure Python. His package compiles a C program which gets called by the Python library, and provides some pickled data to minimize recomputation.

One thing I noticed was the suggestion to use twine to minimize transmission of PyPI passwords in plaintext. I'm not sure why pip doesn't use HTTPS to interact with PyPI directly, but I suspect this to be fixed upstream before too long. For now, twine provides a workaround.

Opening a dialogue about depression within the development community


The culture around software development is not nice to developers. While society tends to compensate them well financially, their mental condition is often overlooked. Given how important mental condition is to successful development, one would think employers and educators would pay closer attention and provide resources for developers. This stems from lack of awareness, which in turn is due to stigma discouraging open discussion about these issues. Let's open up that discussion.

In August, Greg Baugues from Twilio will be giving a talk on developers and depression at the Minnesota PHP user group. Now, I'm not a fan of PHP, but this may be one of the most important events for developers in the area this summer. There are quite a few tickets remaining, so please register.

String { get { switch self { ... case let .JSONString(s): return “\“” + s “\“” ... } } } }


And that's it![^1]

This makes the operation they implemented as follows:

~~~ JavaScript
for item in json["blogs"]?["blog"] {
    let id = blog[“id”]
    let name = blog[“name”]
    let needspassword = blog[“needspassword”]
    let url = blog[“url”]

    println(“Blog ID: \(id)”)
    println(“Blog Name: \(name)”)
    println(“Blog Needs Password: \(needspassword)”)
    println(“Blog URL: \(url)”)
}

That's a lot easier, once a proper JSON library is implemented, anyway. Swiftz has the start of one, similar in style to what I'm proposing here.

[^1]: Or close to it anyway. I'm simplifying here. See Swiftz for a more complete JSON library.

Enter your email to subscribe to updates.