MEP115
AuthorJan Decaluwe
StatusDraft
Created05-Mar-2016
MyHDL-version1.0

Background

Traditionally, the myhdl library is often imported using wildcard import, as follows:

from myhdl import *

The obvious convenience is that all objects in the library are readily available. For example:

from myhdl import *

@module
def mod(...)

    s = Signal(intbv(0)[8:])

    @always_comb
    def comb():
        i = intbv(0)[4:0]
        ...

    @instance
    def inst():
        ...

    return comb, inst, ...

sim = Simulation(...)
sim.run()

The rationale behind wildcard import is that MyHDL is like a mini-language in itself that exports many objects. At some point, wildcard imports were considered acceptable in such a context according to some sources, for example for the Tkinter library.

However, the current Python guidelines make it clear that wildcard import should be avoided in production code, except for some very specific applications. From the MyHDL perspective, the disadvantages are the following:

  1. As the Python guidelines state, wildcard import makes it unclear which names are present in the namespace, confusing both readers and many automated tools.
  2. There is a chance that Python built-ins or standard library objects are implicitly shadowed, increasing the potential confusion. Over the years, this has happened twice already with MyHDL, with the bin() function and the enum module.
  3. Some names may have a different meaning in the Python context, adding to the confusion when used unqualified. Examples in MyHDL are module and instance.

Furthermore, the argument of MyHDL as a mini-language is somewhat misleading. It is explicitly intended and encouraged to use MyHDL in conjunction with other Python libraries. That is also what many users are doing. In such scenarios, it becomes increasingly likely that wildcard import causes problems.

The conclusion is that there should be a good way to import MyHDL objects without relying on wildcard import. The goal of this MEP is to investigate the issues and to define a recommended approach to import the myhdl library.

Explicit import

An obvious way to address some of the issues is by an explicit import of the required names. For example:

from myhdl import module, Signal, intbv, always_comb, instance, Simulation

This solves the issue of the potential ambiguity of names. However, it has several disadvantages:

  • the import line can become quite lengthy
  • any required object name has to be added explicitly to the import line
  • all names in the code are still unqualified, which may be confusing to a reviewer

Module import

A straightforward approach is to import the module as is:

import myhdl

This addresses all the issues but has one important disadvantage: some code may look heavy. For example:

import myhdl
...

s = myhdl.Signal(myhdl.intbv(0)[8:])

Types such as Signal and intbv types are used intensively in behavioral descriptions. In this case, qualified names can be an inconvenient distraction to code writers and reviewers.

A dual approach

To find good solution, we take the standpoint of a code reviewer and recognize that not all objects serve the same purpose. Some objects, like Simulation and toVerilog, are typically only used at a few locations in the code. Other objects are used as decorators on functions. They serve as anchor points in the code. Moreover, as functions are used for a lot of different purposes, it is important to define the particular purpose very clearly. For all those objects, qualified names are an appropriate choice.

On the other hand, types such as Signal and intbv are used to describe the detailed actual behavior. In that case, it can be more convenient to use unqualified names.

The conclusion is that a dual approach is appropriate, where some objects are referred to with a qualified name, and others with an unqualified name.

The dual import approach consists of two import lines: the first line for the module itself, the second for a limited set of unqualified names.

The module usage can be made more lightweight without jeopardizing clarity by importing it as the shorthand hdl, as follows:

import myhdl as hdl

This import reads nicely as "import MyHDL as the HDL". Qualified objects also read nicely, for example as "HDL module" and "HDL simulation".

The second line imports a limited set of unqualified type names from the library, such as Signal and intbv.

The example shown earlier now becomes:

import myhdl as hdl
from myhdl import Signal, intbv

@hdl.module
def mod(...)

    s = Signal(intbv(0)[8:])

    @hdl.always_comb
    def comb():
        i = intbv(0)[4:0]
        ...

    @hdl.instance
    def inst():
        ...

    return comb, inst, ...

sim = hdl.Simulation(...)
sim.run()

The recommendation would be that only objects that are used within behavioral descriptions (i.e. within generator code) may be referred to with unqualified names. In case of ambiguity in a particular piece of code, the module shorthand is always available as a fallback solution.

Alternatives

An alternative for the shorthand name hdl is the even shorter name hw, that stands for "hardware". Qualified objects would read nicely as "hardware module" or "hardware simulation".

Another possibility is to define the shorthand name as another namespace object in the library itself. This would enable single line imports as follows:

from myhdl import hdl, Signal, intbv

This would also be a more direct way to suggest the use of recommended shorthand name. On the other hand, this approach may be "too clever", and more confusing than the more explicit dual import strategy.

Decision

To be completed