Modules Vs. Namespace
In many object-oriented languages, classes are the primary means of encapsulation and modularization; each class defines a namespace and controls how and which definitions are externally visible. In addition, classes in many languages define an indivisible unit that must be used as a whole—if you want to use a String concatenation function, you must import and compile against all of String.
Some languages also include a separate, explicit namespace or module system that performs encapsulation in a more general way. Dylan is such a language.
In Dylan, the concepts of compile-unit and import-unit are separated, and classes have nothing specifically to do with either. A library defines items that should be compiled and handled together, while a module defines the namespace. Classes can be placed together in modules, or cut across them, as the programmer wishes. Often the complete definition for a class does not exist in a single module, but is spread across several that are optionally collected together. Different programs can have different definitions of the same class, including only what they need.
For example, consider an add-on library for regex support on String. In some languages, in order for the functionality to be included in strings, the functionality has to be added to the String namespace itself. As soon as you do this, the String class becomes larger, and people who don't need to use regex still have to "pay" for it in increased library size. For this reason these sorts of add-ons are typically placed in their own namespaces and objects. The downside to this approach is that the new functionality is no longer a part of string; instead, it is isolated in its own set of functions that have to be called separately. Instead of myString.parseWith(myPattern)
, which would be the natural organization from an OO point of view, you use something like myPattern.parseString(myString)
, which effectively reverses the ordering.
In addition, under Dylan many interfaces can be defined for the same code, for instance the String concatenation method could be placed in both the String interface, and the "concat" interface which collects together all of the different concatenation functions from various classes. This is more commonly used in math libraries, where functions tend to be applicable to widely differing object types.
A more practical use of the interface construct is to build public and private versions of a module, something that other languages include as a "bolt on" feature that invariably causes problems and adds syntax. Under Dylan the programmer can simply place every function call in the "Private" or "Development" interface, and collect up publicly accessible functions in "Public". Under Java or C++ the visibility of an object is defined in the code itself, meaning that to support a similar change the programmer would be forced to re-write the definitions completely, and could not have two versions at the same time.
Read more about this topic: Dylan (programming Language)