In Scheme R7RS there is both a load and include form.
Include is described as:
Semantics: Both include and include-ci take one or
more filenames expressed as string literals, apply an
implementation-specific algorithm to find corresponding files, read
the contents of the files in the specified order as if by repeated
applications of read, and effectively re- place the include or
include-ci expression with a begin expression containing what was read
from the files. The difference between the two is that include-ci
reads each file as if it began with the #!fold-case directive, while
include does not. Note: Implementations are encouraged to search for
files in the directory which contains the including file, and to
provide a way for users to specify other directories to search.
Load is described as:
An implementation-dependent operation is used to trans- form filename
into the name of an existing file con- taining Scheme source code. The
load procedure reads expressions and definitions from the file and
evalu- ates them sequentially in the environment specified by
environment-specifier. If environment-specifier is omitted,
(interaction-environment) is assumed. It is unspecified whether the
results of the expres- sions are printed. The load procedure does not
af- fect the values returned by current-input-port and
current-output-port. It returns an unspecified value. Rationale: For
portability, load must operate on source files. Its operation on other
kinds of files necessarily varies among implementations.
What is the rationale for the two forms? I assume it is historic. Is there any import semantic difference between the two forms? I see that load can optionally include an environment specifier and include doesn't have that. And include-ci has no direct equivalent using load. But comparing load and include alone, what is the difference and is it important?
I think the critical difference is that include is syntax (or in traditional Lisp terms, it is a macro) while load is a function. In traditional Lisp terms (there will be a much more formal definition of this in Scheme terms which I am not competent to give) this means that include does its work at macro-expansion time, while load does its work at evaluation time. These times can be very different for an implementation which has a file compiler: macro-expansion time happens during compilation of files, while evaluation happens only much later, when the compiled files are loaded.
So, if we consider two files, f1.scm containing
(define foo 1)
(include "f2.scm")
and f2.scm containing
(define bar 2)
then if you load, or compile f1.scm it is exactly the same as if you had loaded or compiled a file fe.scm which contained:
(define foo 1)
(begin
(define bar 2))
which in turn is the same as if fe.scm contained:
(define foo 1)
(define bar 2)
In particular this inclusion of the files happens at macro-expansion time, which happens when the compiler runs: the object file (fasl file) produced by the compiler will include compiled definitions of foo and bar, and will not in any way depend on f2.scm or its compiled equivalent existing.
Now consider f3.scm containing:
(define foo 1)
(load "f2")
(note I have assumed that (load "f2") (as opposed to (load "f2.scm")) loads the compiled file if it can find it, and the source file if it can't: I think this is implementation-dependent).
Loading the source of this file will do the same thing as loading f1.scm: it will cause foo and bar to be defined. But compiling this file will not: it will produce a compiled file which, when it is later loaded will try to load either the source or compiled versions of f2.scm. If that file exists, at load time, then it will be loaded and the effect will be the same as the include case. If it does not exist at load time, bad things will happen. Compiling f1.scm will not cause the definitions in f2.scm to be compiled.
Depending on your background it might be worth comparing this to, say, C-family languages. What include does is what #include does: it splices in source files as they are read, and in C (as in many Scheme/Lisp systems) this happens as the files are compiled. What load does is to load code at runtime, which, in C, you would need to do by invoking the dynamic linker or something.
Historically, Lisp implementations did not offer module systems.
Large programs used load in order to run a set of instructions, the load function runs a REPL script by reading S-expressions from a file, one by one, and passing them to eval.
Include, on the other hand, is used to inline the code read from a file into the your code. It does not evaluate the code.
...replace the include or include-ci expression with a begin expression containing what was read from the files
The added 'begin' prepares the code read from the file to be evaluated sequentially.
Sources: Question quotes ,Racket docs
Related
I'm moderately new to common lisp, but have extended experience with other 'separate compilation' languages (think C/C++/FORTRAN and such)
I know how to do an ASDF system definition. I know how to separate stuff in packages. I'm using SBCL, by the way.
The question is this: what's the best practice for splitting code (large packages) between .lisp files? I mean, in C there are include files, while lisp lives with the current image state. So with multiple files I need to handle dependencies or serial order in the system definition. But without something like forward declarations it's painful.
Simple example on what I want to do: I have, for example, two defstructs that are part of the same bigger data structure (like struct1 is a parent of some set of struct2). Some functions works on one, some other works on the other and some other use both.
So I would have: a packages.lisp, a fun1.lisp (with the first defstruct and related functions), a fun2.lisp (with the other defstruct and functions) and a funmix.lisp (with functions that use both). In an ideal world everything is sealed and compiling these in this order would be fine. As most of you know, this in practice almost never happen.
If I need to use struct2 functions from the struct1 ones I would need to either reorder or add a dependency. But then if there's some kind of back call (that can't be done with a closure) I would have struct1.lisp depending on struct2.lisp and vice-versa which is obviously not valid. So what? I could break the loop putting the defstruct in a separate file (say, structs.lisp) but what if either of the struct's function need to access the common functions in the third file? I would like to avoid style notes.
What's the common way to solve this, i.e. keeping loosely related code in the same file but still be able to interface to other ones. Is the correct solution to seal everything in a compilation unit (a single file)? use a package for every file with exports?
Lisp dependencies are simple, because in many cases, a Lisp implementation doesn't need to process the definition of something in order to compile its use.
Some exceptions to the rule are:
Macros: macros must be loaded in order to be expanded. There is a compile-time dependency between a file which uses macro and the file which defines them.
Packages: a package foo must be defined in order to use symbols like foo:bar or foo::priv. If foo is defined by a defpackage form in some foo.lisp file, then that file has to be loaded (either in source or compiled form).
Constants: constants defined with defconstant should be seen before their use. Similar remarks apply to inline functions, compiler macros.
Any custom things in a "domain specific language" which enforces definition before use. E.g. if Whizbang Inference Engine needs rules to be defined when uses of the rules are compiled, you have to arrange for that.
For certain diagnostics to be suppressed like calls to undefined functions, the defining and using files must be taken to be as a single compilation unit. (See below.)
All the above remarks also have implications for incremental recompilation.
When there is dependency like the above between files so that one is a prerequisite of the other, when the prerequisite is touched, the dependent one must be recompiled.
How to split code into files is going to be influenced by all the usual things: cohesion, coupling and what have you. Common-Lisp-specific reasons to keep certain things together in one file is inlining. The call to a function which is in the same file as the caller may be inlined. If your program supports any in-service upgrade, the granularity of code loading is individual files. If some functions foo and bar should be independently redefinable, don't put them in the same file.
Now about compilation units. Suppose you have a file foo.lisp which defines a function called foo and bar.lisp which calls (foo). If you just compile bar.lisp, you will likely get a warning that an undefined function foo has been called. You could compile foo.lisp first and then load it, and then compile bar.lisp. But that will not work if there is a circular reference between the two: say foo.lisp also calls (bar) which bar.lisp defines.
In Common Lisp, you can defer such warnings to the end of a compilation unit, and what defines a compilation unit isn't a single file, but a dynamic scope established by a macro called with-compilation-unit. Simply put, if we do this:
(with-compilation-unit
(compile-file "foo.lisp") ;; contains (defun foo () (bar))
(compile-file "bar.lisp")) ;; contains (defun bar () (foo))
If a compile-file isn't surrounded by with-compilation-unit then there is a compilation unit spanning that file. Otherwise, the outermost nesting of the with-compilation-unit macro determines the scope of what is in the compilation unit.
Warnings about undefined functions (and such) are deferred to the end of the compilation unit. So by putting foo.lisp and bar.lisp compilation into one unit, we suppress the warnings about either foo or bar not being defined and we can compile the two in any order.
Build systems use with-compilation-unit under the hood, as appropriate.
The compilation unit isn't about dependencies but diagnostics. Above, we don't have a compile time dependency. If we touch foo.lisp, bar.lisp doesn't have to be recompiled or vice versa.
By and large, Lisp codebases don't have a lot of hard dependencies among the files. Incremental compilation often means that just the affected files that were changed have to be recompiled. The C or C++ problem that everything has to be rebuilt because a core header file was touched is essentially nonexistent.
but what if
No matter how you first organize your code, if you change it significantly you are going to have to refactor. IMO there is no ideal way of grouping dependencies in advance.
As a rule of thumb it is generally safe to define generic functions first, then types, then actual methods, for example. For non-generic functions, you can cut circular dependencies by adding forward declarations:
(declaim (ftype function ...))
Having too much circular dependency is a bit of a code smell.
Is the correct solution to seal everything in a compilation unit
Yes, if you group the definitions in the same compilation unit (the same file), the file compiler will be able to silence the style notes until it reaches the end of file: at this point it knows if there are still missing references or if all the cross-references are resolved.
But then if there's some kind of back call (that can't be done with a closure)
If you have a specific example in mind please share, but typically you can define struct1 and its functions in a way that can be self-contained; maybe it can accept a map that binds event names to callbacks:
(make-struct-1 :callbacks (list :on-empty one-is-empty
:on-full one-is-full))
Similarly, struct2 can accept callbacks too (Dependency Injection) and the main struct ties them using closures (?).
Alternatively, you can design your data-structures so that they signal conditions, and the in the caller code you intercept them to bind things together.
Several weeks ago, SBCL updated 2.0.2 and brought the Block compilation feature. I have read this article to understand what it is.
I have a question, what's the difference between (declaim (inline 'some-function)) and Block compilation? Block compilation is automatic by the compiler?
Thanks.
Inline compilation is a specific optimization technique. A function being called is directly integrated into the calling function - usually using its source code - and then compiled.
This means that the inlined function might not be inlined only in one function, but in multiple functions.
Advantage: the overhead of calling a function disappears.
Disadvantage: the code size increases and the calling function(s) needs to be recompiled, when the inlined function changed and we want this change to become visible. Macros have the same problem.
Block compilation means that a bunch of code gets compiled together with different semantic constraints and that this enables the compiler to do a bunch of new optimizations.
Common Lisp has in the standard support for block compilation of single files. It allows the file compiler to assume that a file is such a block of code.
Example from the Common Lisp standard:
3.2.2.3 Semantic Constraints
A call within a file to a named function that is defined in the same file refers to that function, unless that function has been declared notinline. The consequences are unspecified if functions are redefined individually at run time or multiply defined in the same file.
This allows the code to call a global function and not use the symbol's function cell for the call. Thus this disables late binding for global function calls - in this file and for functions in this file.
It's not said how this can be achieved, but the compiler might just allocate the code somewhere and the calls just jump there.
So this part of block compilation is defined in the standard and some compilers are doing that.
Block compilation for multiple files
If the file compiler can use block compilation for one file, then what about multiple files? A few compilers can also tell the file compiler that several files make a block for compilation. CMUCL does that. SBCL was derived and simplified from CMUCL and lacks it until now. I think Lucid Common Lisp (which is no longer actively sold) did support something like that, too.
Might be useful to add this to SBCL, too.
I need to compile a Chicken Scheme project containing multiple source files, but I'm getting errors.
According to the manual and this SO answer, I need to put (declare)s in my sources. Why the compiler can't just see that I'm importing the other source is beyond me, but meh.
The problem is, even if I put the (declare)s in, the compiler complains about the (import)s and (use)s.
infinity.filesystem.scm:
(use bindings filepath posix)
(declare (uses infinity.general.scm))
(load-relative "infinity.general.scm")
(module infinity.filesystem (with-open-file make-absolute-path with-temporary-directory with-chdir)
(import scheme filepath posix infinity.general)
(begin-for-syntax
(use bindings chicken)
(import infinity.general))
...etc...
infinity.general.scm:
(declare (unit infinity.general.scm))
(require-extension srfi-1 srfi-13 format data-structures ansi-escape-sequences basic-sequences)
(module infinity.general (bind+ format-ansi repeat-string join-strings pop-chars! inc! dec!
take* drop* take-right* drop-right* ends-with? take-where)
(import scheme chicken srfi-1 srfi-13 data-structures ansi-escape-sequences basic-sequences bindings ports format)
...etc...
Command:
$ csc -uses bindings.o -uses infinity.general.o -c infinity.filesystem.scm -o infinity.filesystem.o
Compiler says:
Syntax error (import): cannot import from undefined module
and
unbound variable: use
If I just remove the import and use declarations for "infinity.general", the file compiles. However, I have two problems with this:
Will the resulting .o file actually work, in the absence of import and use clauses? Or will it complain about missing code at runtime?
csi requires that my code contains (import) and (use) declarations, whereas csc requires that it does not. I, however, require that my code works in both csi and csc!
How can I solve this, please?
Why the compiler can't just see that I'm importing the other source is beyond me, but meh.
Declares are used to determine dependencies: the compiler needs to know in what order (and if at all) to invoke a particular toplevel, to ensure the right code is initialized before any of the globals from that unit can be used. When everything is being compiled separately, the compiler wouldn't know when to insert calls to toplevels. The -uses switch you pass to csc is redundant: csc -uses foo is equivalent to putting (declare (uses foo)) in the source code. Passing -uses foo.o doesn't do anything with the file foo.o as far as I can tell.
In your code snippet, you're using load, which is not the correct way to include code at compile-time: load will read and evaluate the target file at run time. Instead, you should omit the load completely: the declare already takes care of the dependency; you just need to link them together.
Also, it's not very common to use filenames as module/unit names, though it should work.
If I just remove the import and use declarations for "infinity.general", the file compiles. However, I have two problems with this:
1) Will the resulting .o file actually work, in the absence of import and use clauses? Or will it complain about missing code at runtime?
You'll need to keep the import expressions, or the program shouldn't compile. If it does compile, there's something strange going on. You don't need use when you link everything together statically. If you're using dynamic linking, you will get a runtime error.
The error you get about unbound variable: use is because you're using use in a begin-for-syntax block. You'll probably just need to (import-for-syntax chicken), as per your other SO question.
2) csi requires that my code contains (import) and (use) declarations, whereas csc requires that it does not. I, however, require that my code works in both csi and csc!
It looks like you're approaching this too quickly: You are writing a complete program and at the same time trying to make it run compiled and interpreted, without first building an understanding of how the system works.
At this point, it's probably a good idea to experiment first with a tiny project consisting of two files. Then you can figure out how to compile an executable that works from code that also works in the interpreter. Then, use this knowledge to build the actual program. If at any point something breaks, you can always go back to the minimal case and figure out what you're doing differently.
This will also help in getting support, as you would be able to present a complete, but minimal set of files, and people will be able to tell you much quicker where you went wrong, or whether you've found a bug.
I am using clisp 2.49 on Windows 7. I start the command window and navigate to the directory with the .lisp file. I then run clisp and try to load the file. I get error "there is no package with name C" on it. C in this case refers to drive C since the absolute path of the fill starts with C:/../../lispFile. I have also tried loading the file on Allegro CL but got the same error.
Below is a screen cap of the error message.
error message
EDIT:
I have identified that the line of code that was causing the error message is:
(defparameter c:\\workdir\\aima\\ (truename "~/public_html/code/");
"The root directory where the code is stored.")
I am not sure if the syntax is incorrect.
Solved: I figured out what I did wrong. I was given instructions to modify the lisp file but misunderstood it and replaced the wrong part of the line. Here is the corrected line of code.
(defparameter *aima-root* (truename "c:\\workdir\\aima\\");
"The root directory where the code is stored.")
Note that one can also compute the directory during load time:
(defparameter *aima-root*
(when *load-pathname*
(make-pathname :defaults *load-pathname*
:name nil
:type nil))
"The root directory where the code is stored.")
*load-pathname* is a standard Common Lisp variable and will be bound during load time, to the pathname similar to the one used for the load function. Thus it points to the file being loaded. We then construct a new pathname, with the defaults filled from the load pathname and no name and no pathname type components.
Thus you can set the *aima-root* variable based on that computation and whenever you load the file, the correct directory will be computed.
There are two Common Lisp variables *load-pathname* and *load-truename* bound during load time. The latter is the real physical pathname of the file. Usually I prefer to use the *load-pathname*, which might not be related to the physical pathname structure. Here the code uses the function truename and thus it might be necessary to use the *load-truename*. Common Lisp implementations often record the location where functions and other things are defined, by storing the pathname. Finding the file later is sometimes easier with a pathname than using a truename - because it can have a device/machine independent indirection using logical pathnames.
While not all Common Lisp implementations do compilation to machine code, some of them do, including SBCL and CCL.
In C/C++, if the source files don't change, the binary output of a C/C++ compiler will also not change, assuming the underlying system remains the same.
In a Common Lisp compiler, the compilation is not under the user's direct control, unlike C/C++. My question is that if the Lisp source files haven't changed, under what circumstances will a CL compiler compile the code more than once, and why? If possible, a simple illustrative example would be helpful.
I think that the question is based on some misconceptions. The compiler doesn't compile files, and it's not something that the user has no control over. The compiler is quite readily available through the compile function. The compiler operates on code, not on files. E.g., you can type at the REPL
CL-USER> (compile nil (list 'lambda (list 'x) (list '+ 'x 'x)))
#<FUNCTION (LAMBDA (X)) {100460E24B}>
NIL
NIL
There's no file involved at all. However, there is also a compile-file function, but notice that its description is:
compile-file transforms the contents of the file specified by
input-file into implementation-dependent binary data which are placed
in the file specified by output-file.
The contents of the file are compiled. Then that compiled file can be loaded. (You can also load uncompiled source files, too.) I think your question might boil down to asking under what circumstances would compile-file generate a file with different contents. I think that's really implementation dependent, and it's not really predictable. I don't know that your characterization of compilers for other languages necessarily holds either:
In C/C++, if the source files don't change, the binary output of a
C/C++ compiler will also not change, assuming the underlying system
remains the same.
What if the compiler happens to include a timestamp into the output in some data segment? Then you'd get different binary output every time. It's true that some common scripted compilation/build systems (e.g., make and similar) will check whether previous output can be reused based on whether the input files have changed in the meantime. That doesn't really say what the compiler does, though.
The rules are pretty much the same, but in Common Lisp, it's not a practice to separate declarations from implementation, so usually you must recompile every dependency to be sure. This is a shared practical consequence of dynamic environments.
Imagining there was such separation in place, the following are blantant examples (clearly not exhaustive) of changes that require recompiling specific dependent files, as the output may be different:
A changed package definition
A changed macro character or a change in its code
A changed macro
Adding or removing a inline or notinline declaration
A change in a global type or function type declaration
A changed function used in #., defvar, defparameter, defconstant, load-time-value, eql specializer, make-load-form generated code, defmacro et al (e.g. setf expanders)...
A change in the Lisp compiler, or in the base image
I mean, you can see it's not trivial to determine which files need to be recompiled. Sometimes, the answer is "all subsequent files", e.g. changing the " (double-quotes) macro-character, which might affect every literal string, or the compiler evolved in a non-backwards compatible way. In essence, we end where we started: you can only be sure with a full recompile and not reusing fasls across compilations. And sometimes it's faster than determining the minimum set of files that need to be recompiled.
In practice, you end up compiling single definitions a lot in development (e.g. with Slime) and not recompiling files when there's a fasl as old or younger than the source file. Many times, you reuse files from e.g. Quicklisp. But for testing and deployment, I advise clearing all fasls and recompiling everything.
There have been efforts to automate minimum dependency compilation with SBCL, but I think it's too slow when you change the interim projects more often that not (it involves a lot of forking, so in Windows it's either infeasible or very slow). However, it may be a time saver for base libraries that rarely change, if at all.
Another approach is to make custom base images with base libraries built-in, i.e. those you always load. It'll save both compilation and load times.