Modules are structures that:
In practice, modules are often used to define data abstractions using information hiding to safeguard its internal state.
Modules are more powerful than the static local variables of C, since modules spread state among several functions, not just one.
There are three major uses for modules:
Here's the pseudocode for a data abstraction in the module-as-object style. It represents a single dictionary object. Note how the module structure bundles the state and behavior together, and the import and export provide security through information hiding:
/*
* Pseudocode for a dictionary module. Usage:
*
* Dictionary.put("mega", "either 1000000 or 1048576");
* print(Dictionary.numberOfEntries());
*/
module Dictionary {
import capacity, String;
export put, get, numberOfEntries;
type Entry = { const key: String; value: String; }
var entries: [Entry] = [Entry](capacity);
var size: int = 0;
func put(key: String, value: String) { ... }
func get(key: String) -> String { ... }
func numberOfEntries() -> int { return size; }
}
In this module
Entry
), two variables (entries
and size
) and three functions (put
, get
, and numberOfEntries
).
size
variable.
So this module gives us only one dictionary. How can we get more? Answer: export a dictionary type! Let’s see that next.
Here our module now contains and exports a type:
/*
* A pseudocode dictionary module exporting a dictionary type. Usage:
*
* DictionaryModule.Dictionary d1, d2, d3;
* Dictionary.put(d2, "mega", "either 1000000 or 1048576");
* print(numberOfEntries(d3));
*/
module DictionaryModule {
import String;
export Dictionary, put, get, numberOfEntries;
type Entry = { const key: String; value: String; }
type Dictionary = {
const capacity: int;
entries: [Entry] = [Entry](capacity);
size: int = 0;
}
func put(d: Dictionary, key: String, value: String) {...}
func get(d: Dictionary, key: String) -> String {...}
func numberOfEntries(d: Dictionary) -> int { return d.size; }
}
Notice how you compile the module only once, but you can declare many variables of the exported type.
The next technical advance is to make the module itself a type, rather than just a plain encapsulation device. This is the module-as-type style. Very few languages would consider such thing a module; instead, they would call it a class.
/*
* A dictionary type. Usage:
*
* var d1, d2, d3: Dictionary;
* d2.put("mega", "either 1000000 or 1048576");
* print(d3.numberOfEntries());
*/
class Dictionary {
import ...
export ...
...
}
The thinking is that classes have instances and modules do not.
Some languages don't have modules, but you can simulate them with classes or closures.
In some languages, such as Java, there is no explicit module construct, but you can get the effect of the module with a class. But since classes have instances and modules don't, you need to be able to make a non-instantiable class. In Java you do this by making the constructor private, and all exported methods public static:
class Counter { private int data; private Counter() {} public static int up(int delta) {data += delta; return data;} public static int down(int delta) {data += delta; return data;} }
In some languages, such as pre-ES6 JavaScript, there is no explicit module construct, but you can get the effect of the module with just functions!
// THIS IS OLD JAVASCRIPT: Don't write like this anymore. var dictionary = function () { var data = {}; return { put: function (k, v) {data[k] = v;}, get: function (k) {return data[k];} }; }();
Modules are generally used with static scoping. They bring up the notions of open and closed scopes. Consider:
function f() {
var x, y, z;
function g() {
var a, b, c;
...
}
module m {
import x;
export j;
var i, j, k;
function h {print k;}
...
}
....
}
In g, are x, y, and z automatically imported or not? Are a, b, and c automatically exported or not? What about in m?
The usual rule is that nothing is ever automatically exported from an inner scope, but when importing we have a choice:
Languages vary in how they handle scoping for modules and functions, for example:
Language | Functions | Modules |
---|---|---|
Modula | optionally closed | closed |
Modula 2, 3 | open | closed |
Ada | open | open |
Euclid | closed | closed |
Turing | optionally closed | ? |
Clu | closed | closed |
Here are some questions useful for your spaced repetition learning. Many of the answers are not found on this page. Some will have popped up in lecture. Others will require you to do your own research.
import
and export
, how do they indicate that certain entities are private? We’ve covered: