1
0
Fork 0
cl-sites/lispcookbook.github.io/cl-cookbook/packages.html

461 lines
18 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="en">
<head>
<meta name="generator" content=
"HTML Tidy for HTML5 for Linux version 5.2.0">
<title>Packages</title>
<meta charset="utf-8">
<meta name="description" content="A collection of examples of using Common Lisp">
<meta name="viewport" content=
"width=device-width, initial-scale=1">
<link rel="icon" href=
"assets/cl-logo-blue.png"/>
<link rel="stylesheet" href=
"assets/style.css">
<script type="text/javascript" src=
"assets/highlight-lisp.js">
</script>
<script type="text/javascript" src=
"assets/jquery-3.2.1.min.js">
</script>
<script type="text/javascript" src=
"assets/jquery.toc/jquery.toc.min.js">
</script>
<script type="text/javascript" src=
"assets/toggle-toc.js">
</script>
<link rel="stylesheet" href=
"assets/github.css">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
</head>
<body>
<h1 id="title-xs"><a href="index.html">The Common Lisp Cookbook</a> &ndash; Packages</h1>
<div id="logo-container">
<a href="index.html">
<img id="logo" src="assets/cl-logo-blue.png"/>
</a>
<div id="searchform-container">
<form onsubmit="duckSearch()" action="javascript:void(0)">
<input id="searchField" type="text" value="" placeholder="Search...">
</form>
</div>
<div id="toc-container" class="toc-close">
<div id="toc-title">Table of Contents</div>
<ul id="toc" class="list-unstyled"></ul>
</div>
</div>
<div id="content-container">
<h1 id="title-non-xs"><a href="index.html">The Common Lisp Cookbook</a> &ndash; Packages</h1>
<!-- Announcement we can keep for 1 month or more. I remove it and re-add it from time to time. -->
<p class="announce">
📢 🤶 ⭐
<a style="font-size: 120%" href="https://www.udemy.com/course/common-lisp-programming/?couponCode=LISPY-XMAS2023" title="This course is under a paywall on the Udemy platform. Several videos are freely available so you can judge before diving in. vindarel is (I am) the main contributor to this Cookbook."> Discover our contributor's Lisp course with this Christmas coupon.</a>
<strong>
Recently added: 18 videos on MACROS.
</strong>
<a style="font-size: 90%" href="https://github.com/vindarel/common-lisp-course-in-videos/">Learn more</a>.
</p>
<p class="announce-neutral">
📕 <a href="index.html#download-in-epub">Get the EPUB and PDF</a>
</p>
<div id="content"
<p>See: <a href="http://www.flownet.com/gat/packages.pdf">The Complete Idiots Guide to Common Lisp Packages</a></p>
<h2 id="creating-a-package">Creating a package</h2>
<p>Heres an example package definition. It takes a name, and you
probably want to <code>:use</code> the Common Lisp symbols and functions.</p>
<pre><code class="language-lisp">(defpackage :my-package
(:use :cl))
</code></pre>
<p>To start writing code for this package, go inside it:</p>
<pre><code class="language-lisp">(in-package :my-package)
</code></pre>
<p>This <code>in-package</code> macro puts you “inside” a package:</p>
<ul>
<li>any new variable or function will be created in this package, aka in the “namespace” of this package.</li>
<li>you can call all this packages symbols directly, without using the package prefix.</li>
</ul>
<p>Just try!</p>
<p>We can also use <code>in-package</code> to try packages on the REPL. Note that on
a new Lisp REPL session, we are “inside” the CL-USER package. It is a
regular package.</p>
<p>Lets show you an example. We open a new .lisp file and we create a new
package with a function inside our package:</p>
<pre><code class="language-lisp">;; in test-package.lisp
(defpackage :my-package
(:use :cl))
(in-package :my-package)
(defun hello ()
(print "Hello from my package."))
</code></pre>
<p>This “hello” function lives inside “my-package”. It is not exported yet.</p>
<p>Continue below to see how to call it.</p>
<h3 id="accessing-symbols-from-a-package">Accessing symbols from a package</h3>
<p>As soon as you have defined a package or loaded one (with Quicklisp,
or if it was defined as a dependency in your <code>.asd</code> system
definition), you can access its symbols with <code>package:a-symbol</code>, using
a colon as delimiter.</p>
<p>For example:</p>
<pre><code class="language-lisp">(str:concat …)
</code></pre>
<p>When the symbol is not exported (it is “private”), use a double colon:</p>
<pre><code class="language-lisp">(package::non-exported-symbol)
(my-package::hello)
</code></pre>
<p>Continuing our example: in the REPL, be sure to be in <code>my-package</code> and not in <code>CL-USER</code>. There you can call “hello” directly:</p>
<pre><code class="language-lisp">CL-USER&gt; (in-package :my-package)
#&lt;PACKAGE "MY-PACKAGE"&gt;
;; ^^^ this creates a package object.
MY-PACKAGE&gt; (hello)
;; ^^^^ the REPL shows you the current package.
"Hello from my package."
</code></pre>
<p>But now, come back to the CL-USER package and try to call “hello”: we get an error.</p>
<pre><code class="language-lisp">MY-PACKAGE&gt; (in-package :cl-user)
#&lt;PACKAGE "COMMON-LISP-USER"&gt;
CL-USER&gt; (hello)
=&gt; you get the interactive debugger that says:
The function COMMON-LISP-USER::HELLO is undefined.
(quit)
</code></pre>
<p>We have to “namespace” our hello function with its package name:</p>
<pre><code class="language-lisp">CL-USER&gt; (my-package::hello)
"Hello from my package."
</code></pre>
<p>Lets export the function.</p>
<h3 id="exporting-symbols">Exporting symbols</h3>
<p>Augment our <code>defpackage</code> declaration to export our “hello” function like so:</p>
<pre><code class="language-lisp">(defpackage :my-package
(:use :cl)
(:export
#:hello))
</code></pre>
<p>Compile this (<code>C-c C-c</code> in Slime), and now you can call</p>
<pre><code class="language-lisp">CL-USER&gt; (my-package:hello)
</code></pre>
<p>with a single colon.</p>
<p>You can also use the <code>export</code> function:</p>
<pre><code class="language-lisp">(in-package :my-package)
(export #:hello)
</code></pre>
<p>Observation:</p>
<ul>
<li>exporting <code>:hello</code> without the sharpsign (<code>#:hello</code>) works too, but it will always create a new symbol. The <code>#:</code> notation does not create a new symbol. More precisely: it doesnt <em>intern</em> a new symbol in our current package. It is a detail and at this point, a personal preference to use it or not. It can be helpful to not clutter our symbols namespace, specially when we import and re-export symbols from other libraries. That way, our editors symbols completion only shows relevant results. It is not useful for us at this point, dont worry.</li>
</ul>
<p>Now we might want to import individual symbols in order to access them right
away, without the package prefix.</p>
<h3 id="importing-symbols-from-another-package">Importing symbols from another package</h3>
<p>You can import exactly the symbols you need with <code>:import-from</code>:</p>
<pre><code class="language-lisp">(defpackage :my-package
(:import-from :ppcre #:regex-replace)
(:use :cl))
</code></pre>
<p>Now you can call <code>regex-replace</code> from inside <code>my-package</code>, without the <code>ppcre</code> package prefix. <code>regex-replace</code> is a new symbol inside your package. It is not exported.</p>
<p>Sometimes, we see <code>(:import-from :ppcre)</code>, without an explicit
import. This helps people using ASDFs <em>package inferred system</em>.</p>
<p>You can also use the <code>import</code> function from outside a package definition:</p>
<pre><code class="language-lisp">CL-USER&gt; (import 'ppcre:regex-replace)
CL-USER&gt; (regex-replace …)
</code></pre>
<h3 id="importing-all-symbols">Importing all symbols</h3>
<p>It is a better practice to carefully choose what symbols you import from another package (read below), but we can also import all symbols at once with <code>:use</code>:</p>
<pre><code class="language-lisp">(defpackage :my-package
(:use :cl :ppcre))
</code></pre>
<p>Now you can access all variables, functions and macros of <code>cl-ppcre</code> from your <code>my-package</code> package.</p>
<p>You can also use the <code>use-package</code> function:</p>
<pre><code class="language-lisp">CL-USER&gt; (use-package 'cl-ppcre)
</code></pre>
<h3 id="about-use-ing-packages-being-a-bad-practice">About “use”-ing packages being a bad practice</h3>
<p><code>:use</code> is a well spread idiom. You could do:</p>
<pre><code class="language-lisp">(defpackage :my-package
(:use :cl :ppcre))
</code></pre>
<p>and now, <strong>all</strong> symbols that are exported by <code>cl-ppcre</code> (aka <code>ppcre</code>)
are available to use directly in your package. However, this should be
considered bad practice, unless you <code>use</code> another package of your
project that you control. Indeed, if the external package adds a
symbol, it could conflict with one of yours, or you could add one
which will hide the external symbol and you might not see a warning.</p>
<p>To quote <a href="https://gist.github.com/phoe/2b63f33a2a4727a437403eceb7a6b4a3">this thorough explanation</a> (a recommended read):</p>
<blockquote>
<p>USE is a bad idea in contemporary code except for internal packages that you fully control, where it is a decent idea until you forget that you mutate the symbol of some other package while making that brand new shiny DEFUN. USE is the reason why Alexandria cannot nowadays even add a new symbol to itself, because it might cause name collisions with other packages that already have a symbol with the same name from some external source.</p>
</blockquote>
<h2 id="list-all-symbols-in-a-package-do-external-symbols">List all Symbols in a Package (do-external-symbols)</h2>
<p>Common Lisp provides some macros to iterate through the symbols of a
package. The two most interesting are:
<a href="http://www.lispworks.com/documentation/HyperSpec/Body/m_do_sym.htm"><code>DO-SYMBOLS</code> and <code>DO-EXTERNAL-SYMBOLS</code></a>. <code>DO-SYMBOLS</code> iterates over the
symbols accessible in the package and <code>DO-EXTERNAL-SYMBOLS</code> only iterates over
the external symbols (you can see them as the real package API).</p>
<p>To print all exported symbols of a package named “PACKAGE”, you can write:</p>
<pre><code class="language-lisp">(do-external-symbols (s (find-package "PACKAGE"))
(print s))
</code></pre>
<p>You can also collect all these symbols in a list by writing:</p>
<pre><code class="language-lisp">(let (symbols)
(do-external-symbols (s (find-package "PACKAGE"))
(push s symbols))
symbols)
</code></pre>
<p>Or you can do it with <a href="http://www.lispworks.com/documentation/HyperSpec/Body/06_a.htm"><code>LOOP</code></a>.</p>
<pre><code class="language-lisp">(loop for s being the external-symbols of (find-package "PACKAGE")
collect s)
</code></pre>
<h2 id="package-nickname">Package nickname</h2>
<h4 id="package-local-nicknames-pln">Package Local Nicknames (PLN)</h4>
<p>Sometimes it is handy to give a local name to an imported package to
save some typing, especially when the imported package does not
provide nice global nicknames.</p>
<p>Many implementations (SBCL, CCL, ECL, Clasp, ABCL, ACL, LispWorks &gt;= 7.2…) support Package Local Nicknames (PLN).</p>
<p>To use a PLN you can simply do the following, for example, if youd like to try out a local nickname in an ad-hoc fashion:</p>
<pre><code class="language-lisp">(uiop:add-package-local-nickname :a :alexandria)
(a:iota 12) ; (0 1 2 3 4 5 6 7 8 9 10 11)
</code></pre>
<p>You can also set up a PLN in a <code>defpackage</code> form. The effect of PLN is totally within <code>mypackage</code> i.e. the <code>nickname</code> wont work in other packages unless defined there too. So, you dont have to worry about unintended package name clash in other libraries.</p>
<pre><code class="language-lisp">(defpackage :mypackage
(:use :cl)
(:local-nicknames (:nickname :original-package-name)
(:alex :alexandria)
(:re :cl-ppcre)))
(in-package :mypackage)
;; You can use :nickname instead of :original-package-name
(nickname:some-function "a" "b")
</code></pre>
<p>Another facility exists for adding nicknames to packages. The function <a href="http://www.lispworks.com/documentation/HyperSpec/Body/f_rn_pkg.htm"><code>RENAME-PACKAGE</code></a> can be used to replace the name and nicknames of a package. But its use would mean that other libraries may not be able to access the package using the original name or nicknames. There is rarely any situation to use this. Use Package Local Nicknames instead.</p>
<h3 id="nickname-provided-by-packages">Nickname Provided by Packages</h3>
<p>When defining a package, it is trivial to give it a nickname for
better user experience. But this mechanism is <em>global</em>, a nickname
defined here is visible by all other packages everywhere. If you were
thinking in giving a short name to a package you use often, you can
get a conflict with another package. Thats why <em>package-local</em>
nicknames appeared. You should use them instead.</p>
<p>Heres an example anyways, from the <code>prove</code> package:</p>
<pre><code class="language-lisp">(defpackage prove
(:nicknames :cl-test-more :test-more)
(:export #:run
#:is
#:ok)
</code></pre>
<p>Afterwards, a user may use a nickname instead of the package name to refer to this
package. For example:</p>
<pre><code class="language-lisp">(prove:run)
(cl-test-more:is)
(test-more:ok)
</code></pre>
<p>Please note that although Common Lisp allows defining multiple nicknames for
one package, too many nicknames may bring maintenance complexity to the
users. Thus the nicknames shall be meaningful and straightforward. For
example:</p>
<pre><code class="language-lisp">(defpackage #:iterate
(:nicknames #:iter))
(defpackage :cl-ppcre
(:nicknames :ppcre)
</code></pre>
<h3 id="package-locks">Package locks</h3>
<p>The package <code>common-lisp</code> and SBCL internal implementation packages are locked
by default, including <code>sb-ext</code>.</p>
<p>In addition, any user-defined package can be declared to be locked so that it
cannot be modified by the user. Attempts to change its symbol table or
redefine functions which its symbols name result in an error.</p>
<p>More detailed information can be obtained from documents of
<a href="http://www.sbcl.org/manual/#Package-Locks">SBCL</a> and <a href="https://clisp.sourceforge.io/impnotes/pack-lock.html">CLisp</a>.</p>
<p>For example, if you try the following code:</p>
<pre><code class="language-lisp">(asdf:load-system :alexandria)
(rename-package :alexandria :alex)
</code></pre>
<p>You will get the following error (on SBCL):</p>
<pre><code>Lock on package ALEXANDRIA violated when renaming as ALEX while
in package COMMON-LISP-USER.
[Condition of type PACKAGE-LOCKED-ERROR]
See also:
SBCL Manual, Package Locks [:node]
Restarts:
0: [CONTINUE] Ignore the package lock.
1: [IGNORE-ALL] Ignore all package locks in the context of this operation.
2: [UNLOCK-PACKAGE] Unlock the package.
3: [RETRY] Retry SLIME REPL evaluation request.
4: [*ABORT] Return to SLIME's top level.
5: [ABORT] abort thread (#&lt;THREAD "repl-thread" RUNNING {10047A8433}&gt;)
...
</code></pre>
<p>If a modification is required anyway, a package named
<a href="https://www.cliki.net/CL-PACKAGE-LOCKS">cl-package-lock</a> can be used to ignore package locks. For
example:</p>
<pre><code class="language-lisp">(cl-package-locks:without-package-locks
(rename-package :alexandria :alex))
</code></pre>
<h2 id="see-also">See also</h2>
<ul>
<li><a href="https://gist.github.com/phoe/2b63f33a2a4727a437403eceb7a6b4a3">Package Local Nicknames in Common Lisp</a> article.</li>
</ul>
<p class="page-source">
Page source: <a href="https://github.com/LispCookbook/cl-cookbook/blob/master/packages.md">packages.md</a>
</p>
</div>
<script type="text/javascript">
// Don't write the TOC on the index.
if (window.location.pathname != "/cl-cookbook/") {
$("#toc").toc({
content: "#content", // will ignore the first h1 with the site+page title.
headings: "h1,h2,h3,h4"});
}
$("#two-cols + ul").css({
"column-count": "2",
});
$("#contributors + ul").css({
"column-count": "4",
});
</script>
<div>
<footer class="footer">
<hr/>
&copy; 2002&ndash;2023 the Common Lisp Cookbook Project
<div>
📹 Discover <a style="color: darkgrey; text-decoration: underline", href="https://www.udemy.com/course/common-lisp-programming/?referralCode=2F3D698BBC4326F94358">vindarel's Lisp course on Udemy</a>
</div>
</footer>
</div>
<div id="toc-btn">T<br>O<br>C</div>
</div>
<script text="javascript">
HighlightLisp.highlight_auto({className: null});
</script>
<script type="text/javascript">
function duckSearch() {
var searchField = document.getElementById("searchField");
if (searchField && searchField.value) {
var query = escape("site:lispcookbook.github.io/cl-cookbook/ " + searchField.value);
window.location.href = "https://duckduckgo.com/?kj=b2&kf=-1&ko=1&q=" + query;
// https://duckduckgo.com/params
// kj=b2: blue header in results page
// kf=-1: no favicons
}
}
</script>
<script async defer data-domain="lispcookbook.github.io/cl-cookbook" src="https://plausible.io/js/plausible.js"></script>
</body>
</html>