3.2 libraries and modules
3.2.1 design
Why always contains the first line in the library definition file "Module: dylan-user"?
Natas
What I don't understand is why, in all the code examples I see, the first line in the library definition file is Module: dylan-user
Rob Myers
It's saying where the contents of the file should go, rather than creating anything. Dylan-user is already magically defined, and code needs to live in a module, so declaring code to be in dylan-user avoids problems with having to declare libraries and modules before you can declare libraries and modules.
> I don't understand why the Module: statement is needed, if libraries
> are at the top of the hierarchy, i.e., libraries contain modules.
> Doesn't this statement say that the time library is in the
> dylan-user module?
I should know this one. :-) I think it's also because code has to be in modules. :-) Hopefully someone can give a better answer than this.
 
Bascially, the *text* of a Dylan /program/ consists of zero or more /source records/, each of which contains zero or more /top-level forms/. A top-level form is essentially a "define something ... end" macro call or an expression (including, for example, function calls or "begin ... end" statement blocks). The only thing you can't really have at top level are exception handlers. Definer macro calls *are* conceptually executable code but (at least for libraries and modules) they're always executed at compile time, and they're pretty much independent of order (in theory -- Your Compiler May Vary).
The "Module: foo" line is not part of the Dylan language itself, but of the "Dylan Interchange Format" (also defined in the DRM) for storing Dylan in text files. Each text file constitutes a source record. If you had a development environment like Apple's Technology Release, source records might be in a database, which would store and display the module of that source record in some other way.
The compiler has to know which module a source record belongs to, so that it knows which bindings are visible and where their definition comes from. The *only* /special form/ is "define macro", which can't be renamed or shadowed.
That describes the text of a Dylan program but not the library/module/binding *containment*. Libraries are compile-time entities which are created by calls to "define library" (or, to any macro whose expansion calls that, but I'll ignore that for now). The library itself lives in a global namespace, outside any modules, but the *definition* has to happen in a module where "\library- definer" is visible.
(Similarly modules are created by calls to "define module". Which library they exist in just depends on which other source records they're compiled with -- there must be exactly one "define library" for it to be a valid Dylan program. The module might be exported by the library, but it might not -- it might be a utility module imported by other modules in the library.)
The dylan-user library exists so that you can create a source record in which "\library-definer" is definitely visible; in that source record you can define your library.
Theoretically you could write something like this:
------------------------------------------------------
Module: my-module

define library my-library
  use dylan;
end;
define module my-module
  use dylan;
end;
------------------------------------------------------
and then require the compiler to prove that the calls to "\library-definer" and "\module-definer" here are really calls to the macros with those names exported from the "dylan" module. However, that's (even) more hassle for compiler writers and you could probably increase the complexity of "circular" examples like these until some compilers could cope and others couldn't.
Lastly, the reason for not doing "use dylan;" implicitly is that you might want to use an implementation-specific library/module which exports all the bindings of the Dylan library/module, plus some of its own. FunDev has "functional-dylan" as well as versions of "dylan" which do some magic on "\+" etc. to support generic arithmetic; both FunDev and Gwydion have "common-dylan".
Gabor Greif
Let's put it this way: Top-level-forms (which generalize "code") are only allowed in modules. Since modules (and their hosting libraries) can only be declared as a top-level-forms, there is a need for some pre-existing module that allows this. Dylan-user module fullfils this purpose.
Why aren't the "define module" declarations nested within the "define library" ones? So you can easily have two libraries which include the same module.
Kim Barrett
The library is by definition the unit of compilation for Dylan.
Bruce Hoult
I don't understand the rules for the "define library" and "define module" declarations themselves. Why aren't the "define module" declarations nested within the "define library" ones?
Does the scope of the "define library" extend to the end of the file? Is it possible to have more than one "define library" declaration in the same file?
Kim Barrett
They are separate so that you can easily have two libraries which include the same module.
Say there are two libraries for two different products, and both use the same utility module. That utility module could be packaged in a separate third library which is used by both of the first two. But that might increase opportunities for configuration problems, and might decrease optimization opportunities due to separate compilation of the product library and the utility library. Kind of like the choice between dynamically linking or statically linking a library. That utility module could have its module definition copied into the two product libraries, but that would likely lead to the usual multiple copies of the same source code problems, so was not seriously considered as a solution to this problem.
Would a type signature of methods at the module level be an improvement?
Greg Sullivan
One shortcoming of Dylan's module system is that you cannot be more specific than names -- i.e. you can't specify the type signature of methods or generic functions at the module level.  At least Java interfaces allow you to specify the names _and_ types of methods that must be implemented.
Kim Barrett
Speaking as one of the designers of the existing module system, I strongly disagree with you on this.  It was in fact completely intentional that Dylan module definitions *don't* contain such information. 
Dave Moon explained it well, in a long-ago (3/3/94) email discussion:
    Dylan does not require programmers to make a textual copy of portions of the definitions of items exported by a module, like a C header file or an  Ada package declaration. 
In my opinion Dylan modules still have a well-defined interface; the difference is that we assume there will be the obvious development tools for printing out that interface, instead of requiring programmers to pretend to be tools and copy text from one file to  another.  (Except of course Dylan still requires programmers to copy the -names- of the exports from their definitions into the define module statement.  We haven't thought of a good way to avoid that.)
Greg Sullivan
Having type signatures as part of the module system would enable better cross-module type checking and better optimization.
Kim Barrett
Having type signatures as part of the module system should do nothing to improve cross-module type checking and optimization. 
The development environment and delivery model assumed by the existing specification of module defining forms is that part of a library that one can compile code wrto and link to is some information provided by the compiler when it processed that library.  One of the things that should be in that information is the stuff needed to compile more efficiently references to the library's bindings.  Type information is only one of many bits that ought to be placed there, including such things as inlining  information, sealing, expected code size (might be used for automatic inlining decisions), expected runtime cost (again useful for inlining), and so on. Much of that can't reasonably be generated by the programmer, and really needs to be done by the compiler.  Given the existence of this repository, it seems pretty silly to make the programmer maintain two independent copies of the type information when the compiler could just as easily generate the needed information by processing the definitions instead of comparing the two copies and complaining about the occasional mismatch.
Hugh Greene
An extension I'd like to see to Dylan is the addition of type information in the export list of a library. The actual implementation types might be more specific than those in the module exports; the export types would allow the compiler to do more optimisation while still allowing the implementation to change. It'd be half-way between the current "loose" and "tight" binding supported by FD
why modules don't nest.
Eric Gouriou
I realize that the "define module" macro should not be extended. I believe  that since it is the level where language bindings are exported, modules  grouping modules (ie modules replacing the current libraries) should be  forbidden.
Hugh Greene
This is, I think, why modules don't currently nest. Also, names of nested
modules might clash with binding names in the same module, which would be
really irritating.
3.2.2 goals
abstraction
How is the separation of interface and implementation done? Via a set of "define generic" and "define abstract class" forms and .
Nick Kramer
No such separation via the module system (In my opinion, this is a gaping hole in the language). The module system is pretty good when it comes to managing namespaces, but it has no concept of contracts or interfaces. You can export the class, but you can't specify which generic functions it has methods for.
Rob MacLachlan
Nick's view is not the consensus in the Gwydion group. It's true that the module system doesn't seperate interfaces and implementations. Instead, it seperates arbitrary chunks of Dylan code, some of which may be interfaces and some of which may be implementations. In Dylan, an interface is primarily defined by a set of "define generic" and "define abstract class" forms.
P T Withington
I recall the recommended practice to have an interface module that creates the names and then any number of implementation modules that will assign definitions to the names.

The section Procotol Design, pp. 214++ in "Dylan Programming", is the place you want to be looking,
Module: dylan-user
// Library definition
define library say
  // Interface modules
  export say, say-implementor;
  // Substrate libraries
  use format-out;
  use dylan;
end library say;
// Protocol interface
define module say
  create say;
end module say;
// Implementor interface
define module say-implementor
  use say, export: all;
  use format-out, export: all;
end module say-implementor;
// Implementation module
define module say-implementation
  use say;
  use dylan;
end module say-implementation;
Separating abstraction level via rename at the module level
 
for Chimp, I mostly just import the low-level, and export it under my high level names:
define module chimp-MPI
   use chimp-low-level,
     rename:{
       %chp-recv => MPI-Receive,
       %chp-recv-nb => MPI-NB-Receive,
       ... }
   export: all;
end module chimp-MPI;
Harley Davis
There already is a way to do what you're doing in Dylan: Just define a new variable which has the value of the previous one. For instance (excuse any syntax errors):
define variable MBI-Receive %chp-recv;
define variable MBI-NB-Receive %chp-recv-nb;
So I don't see that this particular feature gives Dylan any extra power.
Andy
In what way is introducing a new variable the same as introducing an 'alias'?
namespace mangement
What are the scopes of namespaces
  • namespaces in Dylan, and their applicable scope;

Namespace
Scope
library
global
module
per library
constant or variable
per module
symbol or keyword
global
How does a coder prevent scoping clashes?
Johan Ovlinger
I assume that there are scoping constructs so that two different method using the same naming don't interfere with each other?
Scott McKay
Of course, this has all been done in Lisp (CLOS) and Dylan. Generic functions are what you use to extend functionality, packages (or modules) are what you use to prevent clashes.
How does a client handle scoping clashes?
Patrick D. Logan
Many of the C++ libraries I can think off hand use prefixes in their names. This is essentially an ad hoc solution. (What if two vedors choose the same prefix?) And not very pretty.
[...]
Kim Barrett
This problem was considered and dealt with in the design of Dylan.
Libraries are the place where the regression is terminated.
  • A provider's library contains a define library form that names the modules exported from the library.
  • A client's library contains a define library form that names the libraries that are used, including the modules that are imported.
    (With module renaming allowed, just like variable renaming when importing variables into a module, in order to resolve name conflicts).
While a define library form contains a name for the library, that name isn't actually important. Specifically, the library names in the client's imports don't really have anything to do with the provider's library name. Rather, the association between library names in the client's imports and the provider's product is made in some extra-lingual implementation-defined manner. This mechanism can't really be portable because it necessarily deals with such issues as filesystems and their naming conventions (we could have bumped the problem up to an implementation- defined mechanism for mapping from "generic, portable" filenames to actual filenames, but didn't), and so on.
We intentionally made no attempt to specify the specifics of such a mechanism in order to provide as much latitude as possible to implementors in this area. However, just to make it a little clearer, here are sketches of a couple of possible ways it could be done:
  • Edit a standard configuration file associated with the client library, specifying the mapping from library names used by the client to the filename where the used library is found.
  • Drag and drop the icon for the used library onto the icon for the client library.
All of this is in the DIRM, though perhaps not as obvious as it could be.
 
 
 
 
What are the impacts of the module system? Puts the namespace naming into the consumer's hand
Harley Davis
I think the name conflict problem is a fairly minor issue in the overall scheme of things.
The fact is that the C & C++ library market has not suffered at all from this problem; each vendor chooses their ugly prefixes and life goes on.
So I don't think this aspect of  Dylan's module system (or C++ namespaces) will have very much  impact on Dylan's (or C++'s) success or lack thereof.
Wendell Berry
Is that the ultimate criterion for having them in the language?
Modules put namespaces (and name choices in general) in the consumers' hands rather than the providers'.
In Dylan the consumer can choose which modules to use (even if they have the same module name) and which variables to use (even if they have the same variable name). The consumer can rename any variable to resolve a conflict or even just to be more meaningful in that consumer's context.
Why have to deal with ugly prefixes, that ultimately don't resolve all possible conflicts, when there is a module system that is
  • easy to implement; and
  • would resolve all conflicts at the disgression of the *consumer*?
No access to the namespace required
Jason
Is it non-Dylan thinking to wish there was access to the namespace?
Mark Craig Chu-Carroll
Two things:
  • Why do you *want* access to the namespace?

    I'm used to be able to much around with symbol bindings in CommonLisp, but I've needed to in Dylan. It's a *lot* cleaner and safer to just use a table.
  • Names don't exist at runtime in Dylan.
If you give up that distinction, and require the implementation to maintain symbol tables at runtime, then you're crippling a huge number of useful optimizations. It can also get terribly confusing, because
     there is *no* global namespace in Dylan.
  • The names of variables depend on the module in which they're used.
  • The names of modules depends on the libraries in which they're used.
  • And the names of libraries depend on the environmental context in which they're compiled!

In most Dylan implementations, a libraries name can be altered by the environment. When you declare a library "A" which imports a library "B", the binding of the name "B" to a particular library is performed by the environment. There is no guarantee that the library that you use as "B" was compiled as "B"; it may have been compiled as "HickeldyGobblyGook".
3.2.3 usage
Good use of module
What are the roles of modules and the definition clauses that modules use?
P T Withington
I recall the recommended practice to have an interface module that creates the names and then any number of implementation modules that will assign definitions to the names.
The section Procotol Design, pp. 214++ in "Dylan Programming", is quoted here and is the place to look for details.
  • a generic function is a separate protocol
    To permit separate libraries to add methods to a Dylan generic function, the module defining the protocol (that is, the modulle defining the generic function) needs to be first

Module: dylan-user
// Library definition
define library say
  // Interface modules
  export say, say-implementor;
  // Substrate libraries
  use format-out;
  use dylan;
end library say;
// Protocol interface
define module say
  create say;
end module say;
// Implementor interface
define module say-implementor
  use say, export: all;
  use format-out, export: all;
end module say-implementor;
// Implementation module
define module say-implementation
  use say;
  use dylan;
end module say-implementation;

The following is qouted from the section Procotol Design, pp. 214++ in "Dylan Programming",

The definition clause can be used to describe the following roles.
Role
Example clause
interface




// Interface class
create <time>;
// shared protocol
// via a re-exported interface
use say, export: all;
client

// Substrate module
use dylan;
implementation

// Interface module
use time;
implementation and interface

// Interface protocol
export say;

These role of clauses get used to build up protocol interfaces, implementator interfaces, and implementation modules

The roles of module
in a library definition
Proposal
Module: dylan-user

// Library definition
define library time
  // Interface module
  export time;
  // Substrate libraries
  use sixty-unit;
  use say;
  use dylan;
end library time;

// Interface module
define module time
  // Classes
  create <time>,
         <time-of-day>,
         <time-offset>;
  // Shared protocol
  use say, export: all;
  use sixty-unit,
    import: { encode-total-seconds },
    export: all;
end module time;
// Implementation module
define module time-implementation
  // External interface
  use time;
  // Substrate modules
  use sixty-unit;
  use say-implementor;
  use dylan;
end module time-implementation;



define library
   export interface time
   prepare implementation
end library






define interface-module time
  create <time>,
            <time-of-day>
            <time-offset>
   shared-protocolls:
      say, export: all;
      sixty-unit,
         import: { encode-total-seconds },
         export: all;
end interface-module



define implementation-module time
  supported-by:
    sixty;
    say-implementor;
    dylan;
end implementation-module

export
Why should I put \ in front of macro and operator exports?
Modules are the unit of interface, libraries are the unit of *compilation*
Eric Gouriou
I will never replace/upgrade those libraries individually, so having them as DLL is useless to me (and I indeed would appreciate having  an option to compile those multiple projects into just one  executable, taking advantage of the added optimization  capabilities).
Chris Double
If you're not going to use the reuse the libraries or replace/upgrade them individually, why make them libraries? Why not just make them modules within a library? This would also take advantage of the added optimization capabilities.
Eric Gouriou
Indeed. And that's exactly why I want the module/library concepts to change, because these "define libraries" group my modules in well separated sets of functionality. If I were to put all the modules in one or even two libraries, the result would be a mess.
A typical example is this "Ego-Extensions" library. I want to keep it as a library, as most of my projects import it. But I do not want to have it as a DLL, as it is mostly a bunch of miscealleanous helper functions/macros that should be inlined and/or dead-code eliminated in each of those projects.