What is a qualified import?

Hi @krmmalik,

What is the need for import qualified for DA.List here?

When you start a new Daml file, by default you have access to all of the functions defined in a “special” module called Prelude. It’s only special in that it is automatically imported in all Daml files.

Daml comes with many other modules, however, but these have to be manually imported. There are multiple ways to do that. Schematically, assuming you have a file Module.daml with content like:

module Module where

one = 1
two = 2

Obviously not a very useful one, but it will serve its purpose. Here are a few examples of how import statements work:

import Module

test = script do
  assert $ one == 1
  assert $ two == 2
  assert $ Module.one == 1
  assert $ Module.two == 2
import Module as M

test = script do
  assert $ one == 1
  assert $ two == 2
  assert $ M.one == 1
  assert $ M.two == 2
import qualified Module as M

test = script do
  assert $ M.one == 1
  assert $ M.two == 2
import qualified Module

test = script do
  assert $ Module.one == 1
  assert $ Module.two == 2
import qualified Module (one)

test = script do
  assert $ Module.one == 1
import Module (one)

test = script do
  assert $ one == 1
  assert $ Module.one == 1

So you have a few options:

  • A naked import Module lets you access all the names in Module either directly as name or “qualified” as Module.name.
  • Adding an as to the import statement changes the prefix used when qualifying an imported name.
  • Adding the qualified keyword restricts the imported name to only their qualified form.
  • Adding a list of names to the import statement restricts the import to just those names.

Now imagine Module.daml has:

module Module where

map = "map"

and you want to write:

import Module

test = script do
  assert $ map == "map" -- compilation error

This is the case described by @anthony: the compiler doesn’t know which map you’re referring to (there is one in Module, but there is also one in Prelude).

You can still qualify the names if you want:

import Module

test = script do
  assert $ Module.map == "map"
  assert $ Prelude.map (*2) [1, 3, 7] == [2, 6, 14]

So, bottom line:

  • There is no error if you have multiple imports that add the same name to the local list of available names.
  • There is an error if you try to use an unqualified version of a name that has been imported multiple times.
  • You can always qualify names at the point of use.

So using a qualified import is not necessary to resolve the ambiguity: you could choose to only qualify the names that do have a conflict.

I simply prefer, as a matter of personal taste, to always qualify all of my imports. I think that makes the code easier to read because, when I look at some of my code, I immediately know where a name comes from. Other people think that makes the code harder to read because all the names have long prefixes. There isn’t really a “right” answer here (except, you know, mine), it really is a matter of personal preference.

7 Likes