[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.lisp

interface packages

Pascal J. Bourguignon

12/31/2015 6:08:00 AM


Following an irc discussion, here is an example, of package use where
we have:

- an interface package exporting a public API (list of symbols),
- an implementation package implementing this public API,
- a client package using this public API.

This interface package doesn't :use any other package (it could :use
other interface packages if it extended them).

;;------------------------------------------------------------------------

(defpackage "FACTORIAL-INTERFACE"
(:use)
(:export "FACTORIAL"))

;;------------------------------------------------------------------------

(defpackage "FACTORIAL-IMPLEMENTATION"
;; what we implement:
(:use "FACTORIAL-INTERFACE")
;; how we implement it:
(:use "COMMON-LISP"))

(in-package "FACTORIAL-IMPLEMENTATION")

(defun factorial (x)
(check-type x (real 0))
(if (plusp x)
(* x (factorial (1- x)))
1))

;;------------------------------------------------------------------------

(defpackage "FACTORIAL-CLIENT"
;; entry point:
(:export "MAIN")
;; how we implement it:
(:use "COMMON-LISP")
(:use "FACTORIAL-INTERFACE"))

(in-package "FACTORIAL-CLIENT")

(defun main ()
(format *query-io* "Enter a positive real: ")
(finish-output *query-io*)
(let* ((x (read *query-io*))
(x! (factorial x)))
(format t "~A! = ~A~%" x x!)
(finish-output)))

;;------------------------------------------------------------------------


cl-user> (factorial-client:main)
Enter a positive real: 42
42! = 1405006117752879898543142606244511569936384000000000
nil
cl-user>


--
__Pascal Bourguignon__

Croire en l'histoire officielle, c'est croire des criminels sur parole.
-- Simone WEIL (1909-1943) philosophe Française.
2 Answers

TwirlwT

12/31/2015 12:46:00 PM

0

El jueves, 31 de diciembre de 2015, 7:08:32 (UTC+1), informatimago escribió:
> Following an irc discussion, here is an example, of package use where
> we have:
>
> - an interface package exporting a public API (list of symbols),
> - an implementation package implementing this public API,
> - a client package using this public API.
>
> This interface package doesn't :use any other package (it could :use
> other interface packages if it extended them).
>
> ;;------------------------------------------------------------------------
>
> (defpackage "FACTORIAL-INTERFACE"
> (:use)
> (:export "FACTORIAL"))
>
> ;;------------------------------------------------------------------------
>
> (defpackage "FACTORIAL-IMPLEMENTATION"
> ;; what we implement:
> (:use "FACTORIAL-INTERFACE")
> ;; how we implement it:
> (:use "COMMON-LISP"))
>
> (in-package "FACTORIAL-IMPLEMENTATION")
>
> (defun factorial (x)
> (check-type x (real 0))
> (if (plusp x)
> (* x (factorial (1- x)))
> 1))
>
> ;;------------------------------------------------------------------------
>
> (defpackage "FACTORIAL-CLIENT"
> ;; entry point:
> (:export "MAIN")
> ;; how we implement it:
> (:use "COMMON-LISP")
> (:use "FACTORIAL-INTERFACE"))
>
> (in-package "FACTORIAL-CLIENT")
>
> (defun main ()
> (format *query-io* "Enter a positive real: ")
> (finish-output *query-io*)
> (let* ((x (read *query-io*))
> (x! (factorial x)))
> (format t "~A! = ~A~%" x x!)
> (finish-output)))
>
> ;;------------------------------------------------------------------------
>
>
> cl-user> (factorial-client:main)
> Enter a positive real: 42
> 42! = 1405006117752879898543142606244511569936384000000000
> nil
> cl-user>
>
>
> --
> __Pascal Bourguignon__
>
> Croire en l'histoire officielle, c'est croire des criminels sur parole.
> -- Simone WEIL (1909-1943) philosophe Française.

Good example. Perhaps your example should be preceded by (in-package "COMMON-LISP").

And perhaps it should be remarked, to make the message more clear, that:

* (find-symbol "FACTORIAL" (find-package "FACTORIAL-INTERFACE"))

=> FACTORIAL-INTERFACE:FACTORIAL
:EXTERNAL

* (find-symbol "FACTORIAL" (find-package "FACTORIAL-IMPLEMENTATION"))

=> FACTORIAL-INTERFACE:FACTORIAL
:INHERITED

A wish you all (trolls included) a very happy new year, let's see what new exciting things this years bring to us. My aim for the new year is to get stronger and this not only for fighting trolls ))).

Sheers from heart.


Pascal J. Bourguignon

1/1/2016 6:17:00 AM

0

TwirlwT <danieltorridoverde@gmail.com> writes:

> Good example. Perhaps your example should be preceded by (in-package "COMMON-LISP").

Nope.

It's not a good idea to have *PACKAGE* bound to the COMMON-LISP package,
because you will then easily intern symbols, and even define variables,
types, functions, classes with intern CL symbols, that could:

1- collide with definitions from another library than yours,

2- collide with definitions from the implementation itself!

3- break for locked package.


You might consider CL-USER, but I would argue it's even worse, since
there's no telling what package is used by CL-USER. You can assume that
at least CL is used, but implementations may (and do, if only, eg. to
define a QUIT or EXIT function) use other packages too, but foremost,
the user may have shadowed, uninterned and defined anything in it.


Now basically, the question is whether you want to ensure that
defpackage (or any other operator you use outside of your own packages),
will come from CL or not.

One good way to do it would be to qualify those operators:

(cl:defpackage â?¦)


Now look:

(defpackage "cl" (:export "defpackage"))

(setf (readtable-case *readtable*) :preserve)
(LOAD "yourfile.lisp")

So instead you would write:

(|CL|:|DEFPACKAGE| â?¦)

(notice that clisp prints symbols like that with printing with
*print-readable* and *print-escape* are true).

Now look:

(set-macro-character #\| 'funny-pipe-reader)
(load "yourfile.lisp")


Given that the caller controls the readtables, you don't really control
anything in your source files: they can be processed by any kind of
tools.

What the CL standard gives you however, is that any tool that respects
the semantic constraints for a CL implementation, will be able to
"access" the meaning of any program that respect the semantic
constraints for a CL program (that is conforming code).

But this doesn't prevent your code to be processed (or even executed),
by supersets of the CL languages, or by different tools (eg. that
generate documentation, thing that is not specified by the CL standard:
it specifies execution, not documentation).


So you must accept that you don't have the control, when you write a
lisp source. Given this, and given that there are several levels at
which controls can be taken over, from the entity who will compile or
load your source (including, eg. ASDF under the directives you may
provide in your .asd file), the question to ask, is whether it is useful
or whether you may want or need to qualify the symbols of your toplevel
operators.

To:
(defpackage â?¦)
or to:
(cl:defpackage â?¦)
?

The first form could easily make reference to another defpackage
operator than cl:defpackage. For example, it could be
com.informatimago.common-lisp.lisp-reader.package:defpackage or
ibcl:defpackage, with nice features, such as a definite semantics when
redefining a package, or with local package aliases, or hierarchical
packages names, or recoding the toplevel source code so that you can
have an image based development workflow, etc.

cl:defpackage could then denote that you would rather use the native
original CL defpackage operator. There are cases when the difference
may matter, but most of the time, as the writer of the source file you
wouldn't care, and as the loader/compiler of the source file, you would
prefer the source file to use the defpackage operators you need it to
use, instead of cl:defpackage.

Also, concerning the habit of using (in-package <PROJECT-PACKAGE>) at
the start of each source file; it is a similar inconvenience. Surely,
it gives a clear idea of what operators we are refering in the file,
since we can refer to the definition of the specified package. However,
I would argue that this would be better left to the system construction
tool, eg. asdf, to specify in what package (and with what readtable) to
load and compile each source file. A typical example, would be a file
html401.lisp that contains the dtd of HTML 4.01 expressed as defelement
and defattribute forms. This file could be loaded in a package that
defines those two operators as macros expanding to an HTML parser. Or
it could be loaded in a different package that defines those two
operators as macros to define a DSL used to generate HTML pages. If the
package (and readtable) could be specified in asd files, then it would
make the use of such a file without in-package form trivial and
efficient. (This kind of files would occur more frequently that you'd
believe if it was easier to process; for example, you can define a
entity/relation model in such a file, and load it in different
environment (client, server, database), to generate the different
representations of those entities in the different components of a
system.

But even beyond those special cases, it would be a nice feature in
general. For example, CL-STEPPER is a package exporting symbols with
the same names as CL, but with different implementations (for the
special operators and some important macros). When debugging you can
replace CL by CL-STEPPER in your defpackage form and reload the source
to instrument it with the cl-stepper. If the source files didn't
contain in-package forms, then it would be simplier to define a new
stepping package instead of redefining the original package using
cl-stepper, and to load the sources in this stepping package instead of
their original package. You would have two versions of the code loaded,
and could use one or the other depending on whether you need to step and
trace into it or not. Other use cases could be found.


--
__Pascal Bourguignon__ http://www.informat...
â??The factory of the future will have only two employees, a man and a
dog. The man will be there to feed the dog. The dog will be there to
keep the man from touching the equipment.� -- Carl Bass CEO Autodesk