#lang scribble/doc
@(require scribble/manual 
          scribble/eval 
          "guide-utils.rkt"
          "module-hier.rkt"
          (for-label setup/dirs
                     setup/link
                     racket/date
                     (only-in scribble/manual
                              defmodule)))

@title[#:tag "module-basics"]{Module Basics}

Each Racket module typically resides in its own file. For example,
suppose the file @filepath{cake.rkt} contains the following module:

@racketmod[
#:file "cake.rkt"
racket

(provide print-cake)

(code:comment @#,t{draws a cake with @racket[n] candles})
(define (print-cake n)
  (show "   ~a   " n #\.)
  (show " .-~a-. " n #\|)
  (show " | ~a | " n #\space)
  (show "---~a---" n #\-))

(define (show fmt n ch)
  (printf fmt (make-string n ch))
  (newline))
]

Then, other modules can import @filepath{cake.rkt} to use the
@racket[print-cake] function, since the @racket[provide] line in
@filepath{cake.rkt} explicitly exports the definition
@racket[print-cake]. The @racket[show] function is private to
@filepath{cake.rkt} (i.e., it cannot be used from other modules),
since @racket[show] is not exported.

The following @filepath{random-cake.rkt} module imports
@filepath{cake.rkt}:

@racketmod[
#:file "random-cake.rkt"
racket

(require "cake.rkt")

(print-cake (random 30))
]

The relative reference @racket["cake.rkt"] in the import
@racket[(require "cake.rkt")] works if the @filepath{cake.rkt} and
@filepath{random-cake.rkt} modules are in the same
directory. Unix-style relative paths are used for relative module
references on all platforms, much like relative URLs in HTML pages.

@; ----------------------------------------
@section[#:tag "module-org"]{Organizing Modules}

The @filepath{cake.rkt} and @filepath{random-cake.rkt} example
demonstrates the most common way to organize a program into modules:
put all module files in a single directory (perhaps with
subdirectories), and then have the modules reference each other
through relative paths. A directory of modules can act as a
project, since it can be moved around on the filesystem or copied to
other machines, and relative paths preserve the connections among
modules.

As another example, if you are building a candy-sorting program, you
might have a main @filepath{sort.rkt} module that uses other modules
to access a candy database and a control sorting machine. If the
candy-database module itself is organized into sub-modules that handle
barcode and manufacturer information, then the database module could
be @filepath{db/lookup.rkt} that uses helper modules
@filepath{db/barcodes.rkt} and @filepath{db/makers.rkt}.  Similarly,
the sorting-machine driver @filepath{machine/control.rkt} might use
helper modules @filepath{machine/sensors.rkt} and
@filepath{machine/actuators.rkt}.

@centerline[module-hierarchy]

The @filepath{sort.rkt} module uses the relative paths
@filepath{db/lookup.rkt} and @filepath{machine/control.rkt} to import
from the database and machine-control libraries:

@racketmod[
#:file "sort.rkt"
racket
(require "db/lookup.rkt" "machine/control.rkt")
....]

The @filepath{db/lookup.rkt} module similarly uses paths relative to
its own source to access the @filepath{db/barcodes.rkt} and
@filepath{db/makers.rkt} modules:


@racketmod[
#:file "db/lookup.rkt"
racket
(require "barcode.rkt" "makers.rkt")
....]

Ditto for @filepath{machine/control.rkt}:

@racketmod[
#:file "machine/control.rkt"
racket
(require "sensors.rkt" "actuators.rkt")
....]

Racket tools all work automatically with relative paths. For example,

@commandline{racket sort.rkt}

on the command line runs the @filepath{sort.rkt} program and
automatically loads and compiles required modules. With a large enough
program, compilation from source can take too long, so use

@commandline{raco make sort.rkt}

@margin-note{See @secref[#:doc '(lib "scribblings/raco/raco.scrbl")
"make"] for more information on @exec{raco make}.}

to compile @filepath{sort.rkt} and all its dependencies to bytecode
files. Running @exec{racket sort.rkt} will automatically use bytecode
files when they are present.

@; ----------------------------------------
@section{Library Collections}

A @deftech{collection} is a hierarchical grouping of installed library modules.  A
module in a @tech{collection} is referenced through an unquoted,
suffixless path. For example, the following module refers to the
@filepath{date.rkt} library that is part of the @filepath{racket}
@tech{collection}:

@racketmod[
racket

(require racket/date)

(printf "Today is ~s\n"
        (date->string (seconds->date (current-seconds))))
]

When you search the online Racket documentation, the search results
indicate the module that provides each binding. Alternatively, if you
reach a binding's documentation by clicking on hyperlinks, you can
hover over the binding name to find out which modules provide
it.

A module reference like @racketmodname[racket/date] looks like an
identifier, but it is not treated in the same way as @racket[printf]
or @racket[date->string]. Instead, when @racket[require] sees a module
reference that is unquoted, it converts the reference to a
collection-based module path:

@itemlist[

 @item{First, if the unquoted path contains no @litchar{/}, then
       @racket[require] automatically adds a @filepath{/main} to the
       reference. For example, @racket[(require
       @#,racketmodname[slideshow #:indirect])] is equivalent to @racket[(require
       slideshow/main)].}

 @item{Second, @racket[require] implicitly adds a @filepath{.rkt}
       suffix to the path.}

 @item{Finally, @racket[require] resolves the path by searching among
       installed @tech{collections}, instead of treating the path as relative to
       the enclosing module's path.}

]

To a first approximation, a @tech{collection} is implemented as a
filesystem directory. For example, the @filepath{racket} collection is
mostly located in a @filepath{racket} directory within the Racket
installation's @filepath{collects} directory, as reported by

@racketmod[
racket

(require setup/dirs)

(build-path (find-collects-dir) (code:comment @#,t{main collection directory})
            "racket")
]

The Racket installation's @filepath{collects} directory, however, is
only one place that @racket[require] looks for collection directories.
Other places include the user-specific directory reported by
@racket[(find-user-collects-dir)] and directories configured through
the @envvar{PLTCOLLECTS} search path. Finally, and most typically,
collections are found through installed @tech{packages}.

@; ----------------------------------------
@section[#:tag "packages-and-collections"]{Packages and Collections}

A @deftech{package} is a set of libraries that are installed through
the Racket package manager (or included as pre-installed in a Racket
distribution). For example, the @racketmodname[racket/gui] library is
provided by the @filepath{gui} package, while
@racketmodname[parser-tools/lex #:indirect] is provided by the
@filepath{parser-tools} library.@margin-note{More precisely,
@racketmodname[racket/gui #:indirect] is provided by @filepath{gui-lib},
@racketmodname[parser-tools/lex #:indirect] is provided by
@filepath{parser-tools-lib}, and the @filepath{gui} and
@filepath{parser-tools} packages extend @filepath{gui-lib} and
@filepath{parser-tools-lib} with documentation.}

Racket programs do not refer to @tech{packages} directly. Instead,
programs refer to libraries via @tech{collections}, and adding or
removing a @tech{package} changes the set of collection-based
libraries that are available. A single package can supply
libraries in multiple collections, and two different packages can
supply libraries in the same collection (but not the same libraries,
and the package manager ensures that installed packages do not
conflict at that level).

For more information about packages, see @other-manual['(lib
"pkg/scribblings/pkg.scrbl")].

@; ----------------------------------------
@section[#:tag "link-collection"]{Adding Collections}

Looking back at the candy-sorting example of @secref["module-org"],
suppose that modules in @filepath{db/} and @filepath{machine/} need a
common set of helper functions. Helper functions could be put in a
@filepath{utils/} directory, and modules in @filepath{db/} or
@filepath{machine/} could access utility modules with relative paths
that start @filepath{../utils/}. As long as a set of modules work
together in a single project, it's best to stick with relative paths.
A programmer can follow relative-path references without knowing about
your Racket configuration.

Some libraries are meant to be used across multiple projects, so that
keeping the library source in a directory with its uses does not make
sense. In that case, the best option is add a new
@tech{collection}. After the library is in a collection, it can be
referenced with an unquoted path, just like libraries that are
included with the Racket distribution.

You could add a new collection by placing files in the Racket
installation or one of the directories reported by
@racket[(get-collects-search-dirs)]. Alternatively, you could add to
the list of searched directories by setting the @envvar{PLTCOLLECTS}
environment variable.@margin-note*{If you set @envvar{PLTCOLLECTS},
include an empty path in by starting the value with a colon (Unix and
Mac OS) or semicolon (Windows) so that the original search paths are
preserved.} The best option, however, is to add a @tech{package}.

Creating a package @emph{does not} mean that you have to register with
a package server or perform a bundling step that copies your source
code into an archive format. Creating a package can simply mean using
the package manager to make your libraries locally accessible as a
collection from their current source locations.

For example, suppose you have a directory @filepath{/usr/molly/bakery}
that contains the @filepath{cake.rkt} module (from the
@seclink["module-basics"]{beginning} of this section) and other
related modules. To make the modules available as a @filepath{bakery}
collection, either

@itemlist[

 @item{Use the @exec{raco pkg} command-line tool:

        @commandline{raco pkg install --link /usr/molly/bakery}

       where the @DFlag{link} flag is not actually needed when the
       provided path includes a directory separator.}

 @item{Use DrRacket's @onscreen{Package Manager} item from the
       @onscreen{File} menu. In the @onscreen{Do What I Mean} panel,
       click @onscreen{Browse...}, choose the
       @filepath{/usr/molly/bakery} directory, and click
       @onscreen{Install}.}

]

Afterward, @racket[(require bakery/cake)] from any module will import
the @racket[print-cake] function from
@filepath{/usr/molly/bakery/cake.rkt}.

By default, the name of the directory that you install is used both as
the @tech{package} name and as the @tech{collection} that is provided
by the package.  Also, the package manager normally defaults to
installation only for the current user, as opposed to all users of a
Racket installation. See @other-manual['(lib
"pkg/scribblings/pkg.scrbl")] for more information.

If you intend to distribute your libraries to others, choose
collection and package names carefully. The collection namespace is
hierarchical, but top-level collection names are global, and the
package namespace is flat. Consider putting one-off libraries under
some top-level name like @filepath{molly} that identifies the
producer.  Use a collection name like @filepath{bakery} when producing
the definitive collection of baked-goods libraries.

After your libraries are put in a @tech{collection} you can still
use @exec{raco make} to compile the library sources, but it's better
and more convenient to use @exec{raco setup}. The @exec{raco setup}
command takes a collection name (as opposed to a file name) and
compiles all libraries within the collection. In addition, @exec{raco setup} can
build documentation for the collection and add it to the documentation
index, as specified by a @filepath{info.rkt} module in the collection.
See @secref[#:doc '(lib "scribblings/raco/raco.scrbl") "setup"] for
more information on @exec{raco setup}.

@; ----------------------------------------
@section[#:tag "intracollection"]{Module References Within a Collection}

When a module within a collection references another module within the
same collection, either a relative path or a collection path could
work. For example, a @filepath{sort.rkt} module that references
@filepath{db/lookup.rkt} and @filepath{machine/control.rkt} modules within
the same collection could be written with relative paths as in
@secref["module-org"]:

@racketmod[
#:file "sort.rkt"
racket
(require "db/lookup.rkt" "machine/control.rkt")
....]

Alternatively, if the collection is named @filepath{candy}, then
@filepath{sort.rkt} could use collection paths to import the two
modules:

@racketmod[
#:file "sort.rkt"
racket
(require candy/db/lookup candy/machine/control)
....]

For most purposes, these choices will work the same, but there are
exceptions. When writing documentation with @seclink[#:doc '(lib
"scribblings/scribble/scribble.scrbl") "top"]{Scribble}, you must use
a collection path with @racket[defmodule] and similar forms; that's
partly because documentation is meant to be read by client
programmers, and so the collection-based name should appear.
Meanwhile, for @racket[require], using relative paths for references
within a collection tends to be the most flexible approach, but with
caveats.

Relative-path references work much like relative URL references: the
reference is expanded based on the way the enclosing module is
accessed. If the enclosing module is accessed through a filesystem
path, then a relative path in @racket[require] is combined with that
filesystem path to form a new filesystem path. If the enclosing module
is accessed through a collection path, then a relative path in
@racket[require] is combined with that collection path to form a new
collection path. A collection path is, in turn, converted to a
filesystem path, and so the difference between starting with a
filesystem or collection path does not usually matter. Unfortunately,
inherent complexities of path resolution can create differences in
some situations:

@itemlist[

 @item{Through soft links, multiple mount points, or case-insensitive
       filesystems (on an operating system that does not implicitly
       case-normalize paths), there may be multiple filesystem paths
       that refer to the same module file.

       For example, when the current directory is the @filepath{candy}
       collection's directory, the current-directory path that
       @exec{racket} receives on startup may cause @exec{racket
       sort.rkt} to use a different filesystem path than @exec{racket
       -l candy/sort} finds through the library-collection search
       path. In that case, if @filepath{sort.rkt} leads to some
       modules through both relative-path references and
       collection-based references, it's possible that those resolve
       to difference instances of the same source module, creating
       confusion through multiple instantiations.}

 @item{When @seclink["exe" #:doc '(lib
       "scribblings/raco/raco.scrbl")]{@exec{raco exe}} plus
       @seclink["exe-dist" #:doc '(lib
       "scribblings/raco/raco.scrbl")]{@exec{raco distribute}} are
       used to create an executable to run on a different machine, the
       paths of the current machine are likely unrelated to paths on
       the target machine. The @exec{raco exe} tool treats modules
       that are referenced via filesystem paths differently than
       modules reference via collection paths, because only the latter
       make sense to access through reflective operations at run
       time.

       For example, if @exec{raco exe sort.rkt} creates an executable
       that uses @racket[(dynamic-require 'candy/db/lookup #f)] at run
       time, then that @racket[dynamic-require] will fail in the case
       that @filepath{db/lookup.rkt} is resolved relative to the
       filesystem path @racket{sort.rkt} at executable-creation time.}

]

Using only collection-based paths (including using shell commands like
@exec{racket -l candy/sort} and not like @exec{racket sort.rkt}) can
avoid all problems, but then you must only develop modules within an
installed collection, which is often inconvenient. Using relative-path
references consistently tends to be the most convenient while still
working in most circumstances.
