@section Development of Projects using Files and Packages
While in the previous chapter most of the coding was done at the
prompt level, in this chapter the coding is done by using a project
management approach, in separate files. Each time you start a new GDL
project, it is recommended to structure your applications in a modular
fashion. This allows you to incrementally compile and load your
applications. To illustrate the best practice in creating a new GDL
project, we will describe in detail a small application. This
application is created and loaded following the next three steps:
@i{Note: To avoid confusion, at the beginning of each sample code the file name will}
@i{be mentioned with the following notation:} @b{;;--file-name.lisp--}
@i{and in some cases, comments will be added.}
@b{Step 1.} Create a new folder in your HOME folder, named
@b{shock-absorber}. Within this folder create a new folder named
@b{source}.
@b{Step 2.} In the @b{source} directory create the next three lisp
files (the file names used below follow the normal convention, but
your file names can potentially be different):
@b{The first file} will be named @b{package.lisp} and will contain
your package definition as mentioned below:
@sp 1
@cartouche
@smallexample
;;--package.lisp--
(in-package :gdl-user)
(define-package :shock-absorber ;;the name of your new package as key word
(:nicknames :shock :picasso ) ;;the nicknames of your new package
(:use ) ;;the packages used by your new package
(:export #:assembly
;; Exported symbols
))
@end smallexample
@end cartouche
@sp 1
It is also possible to skip the package specification @b{(in-package :gdl-user)}
as presented in this example code, if you refer to the package definition macro
as @b{gdl:define-package}.
Note that you can work directly in the @b{:gdl-user} package, which is
an empty pre-defined package for your use, if you do not wish to make
a new package just for scratch work.
For real projects, however, it is recommended that you make and work
in your own GDL package.
In GDL, the macro @b{define-package} is used to set up a new working package.
Packages defined with @b{gdl:define-package} will implicitly @b{:use}
the GDL package and the Common-Lisp package, so you will have access
to all exported symbols in these packages without prefixing them with
their package name. You may extend this behavior by calling
@b{gdl:define-package} and adding additional packages to use with
@b{(:use ...)}. For example, if you want to work in a package with
access to GDL exported symbols, Common Lisp exported symbols, and
symbols which are defined in other packages like @b{:my-utilities}, you
could set it up as follows:
@sp 1
@cartouche
@smallexample
;;--package.lisp--
(gdl:define-package :shock-absorber
(:nicknames :shock :picasso )
(:use :my-utilities)
(:export #:assembly
;; Exported symbols
))
@end smallexample
@end cartouche
@sp 1
@i{Note: The ``Exported symbols'' option will be addressed in the next
chapter on a real case. However, the fundamental concept is that
symbols are contained in packages, and can be marked as ``internal''
or ``external,'' which is roughly analogous to ``private'' and
``public'' in languages like C++ and Java --- that is, internal
symbols should only be accessed from inside the same package where
they are defined. In the above example, the symbol @b{assembly} is
exported from the @b{:shock-absorber} package. Note that symbols named
in the export list should be prepended with ``#:'' --- this is for
``package hygiene'' reasons which are not important to understand at
this point.}
@b{The second file} will be named @b{assembly.lisp} and will contain
the definition for the toplevel ``assembly'' (i.e. object) of your
application. As you have already seen, this file will contain a GDL
object definition so it will have the following structure:
@image{images/define-object}
As stated in previous chapters, @b{define-object} is the basic macro for defining objects
(i.e. creating classes) in GDL. A GDL object definition in which:
@itemize @bullet
@item @b{class-name} is any non-keyword symbol [i.e. a symbol not preceded by a colon (``:'')]. A GDL Class will be generated for this symbol, so that any name you use will override a previous class if one is already defined with the same name.
@item @b{mixin-list} is a list of other class-names (i.e. object definition names) from which this object will inherit. Note that the standard mixin @b{gdl:vanilla-mixin} gets mixed in automatically with any GDL object and carries some of the basic GDL functionalities (messages).
@item @b{specification-plist} is a plist made up of pairs made from special keywords and expression lists.
@end itemize
For the moment we will exemplify the use of the specification-plist by
defining a cylinder child object named @b{my-cylinder} contained by
the @b{new-object} as mentioned below:
@sp 1
@cartouche
@smallexample
;;-- assembly.lisp--
(in-package :shock-absorber)
(define-object assembly (base-object)
:input-slots ()
:trickle-down-slots ()
:computed-slots ()
:objects ((my-cylinder :type 'cylinder
:length 10
:radius 3))
:hidden-objects ()
:functions ()
:methods ())
@end smallexample
@end cartouche
@sp 1
The @b{:objects} and @b{:hidden-objects} are used to specify a list of
instance specifications, where each instance is considered to be a
``child'' object of the current object, @b{:hidden-objects} serves the
same purpose and has the same syntax, but hidden objects are
considered @b{hidden-children} rather than @b{children} (so they are
not returned by a call to (the children), for example).The inputs to
each object are specified as a plist of inputs and value expressions,
spliced in after the object's name and type specification; in the
presented case @b{:length} and @b{:radius} for the my-cylinder.