> in emacs lisp, if you write ‘foo-frobber, you know it’s probably from the package ‘foo, and that it’s a frobber.
It's a convention, not an actual mechanism. But it's open to interpretations. What does ANIMATED-WINDOW-DRAW mean? Is it supposed to be WINDOW-DRAW in the ANIMATED 'package' or is it DRAW from the ANIMATED-WINDOW package? Probably there is another convention for that.
Note then that in Emacs Lisp the concept package means a software library, where in Common Lisp the concept package means a symbol namespace.
> Whereas in CL, isn’t the norm to use the package system everywhere?
It's widely used, but in slightly different ways. Some use it as a poor module system replacement. Often it is used a way to structure code into larger symbol namespaces. Sometimes you'll find code bases which do everything in one package.
> So you can’t just pass ‘foo-frobber to arbitrary packages and expect it to work.
'Passing to packages' is not a concept in Common Lisp. But you can use symbols from all packages everywhere. There is no enforced hiding mechanism or module system which hides things. The only thing packages actually do is being a namespace for symbols. Thus it is possible to have many symbols with the same name, but they need to be in different packages or need to belong to no package.
> For example, (intern “foo-frobber”) returns a symbol.
It does. It uses at runtime the package bound to the current package to intern the symbol.
The current package is the value of the symbol
*package*
> But can you just pass that plain old symbol between packages without having to explicitly indicate its origin?
You can pass the symbol around. Its package can be queried. If you want to refer to the symbol in written code while being in another package (another symbol namespace) one has four options:
1) use the symbol fully qualified FOO::BAR. Note the two colons.
2) use exported symbols as FOO:BAR. Note the one colon.
3) use the symbol after importing it into the current package as BAR.
4) programmatically lookup the symbol: (find-symbol "BAR" "FOO")
There's only one problem[0] that could bite someone used to the way elisp code is written: when the reader sees e.g. FOO:BAR, or FOO::BAZQUUX, the package FOO must already exist (and AFAIK have BAR exported), otherwise you'll get a reader error. You can't work around it with regular macros, because the error is at read-time, way before macroexpansion-time or compile-time.
This shows up whenever you need to set up some functions using a package before the code defining that package is loaded. This might be a rare use case in general, but it's something that shows up frequently enough when configuring Emacs. The only workaround for CL that I know is programmatic lookup of the symbol via FIND-SYMBOL, or just keeping the problematic code as string and running it through (EVAL (READ-FROM-STRING ...)) when it's safe for reader to parse it. Since Elisp doesn't have a package system, the problem doesn't exist there; at worst you'll get a warning from the byte compiler/interpreter that it doesn't (yet) know what variable or function a symbol represents.
--
[0] - Or at least what I believe to be a problem; I'm half-hoping there's a trivial solution that I'm missing.
Right, these are two limitations in CL at read time (when symbols are read by Lisp):
the package needs to exist and for an exported symbol notation, the symbol actually needs to be exported. The latter makes sense in some way, because the mechanism should warn, when a symbol is used, which is not exported.
One way one might be able to deal with that would be to catch the reader error and create a package on the fly, which then would have these symbols and/or exports some of these. Later, when a DEFPACKAGE is seen, the package could be adjusted to the new package definition. Note that modifying an existing package via DEFPACKAGE has undefined consequences in the standard. Implementations may deal with that, though.
But there are problems with the approach: imagine someone uses FOO:BAR in his source code. But that was a symbol from an old version of that software and now FOO:BAR is no longer exported or even doesn't exist. What now? Should this modify the package? Should it warn? Be an error?
Currently when using Common Lisp and reading a symbol with a non-existing package, the Lisp system shows an error. I can't remember what the Lisp Machine did, but it easily could have presented a restart option to create the package and go on.
LispWorks does that: it shows an error and provides a restart.
CL-USER 89 > (read-from-string "LOL::ROTFL")
Error: Reader cannot find package LOL.
1 (continue) Create the LOL package.
2 Use another package instead of LOL.
3 Try finding package LOL again.
4 (abort) Return to top loop level 0.
Type :b for backtrace or :c <option number> to proceed.
Type :bug-form "<subject>" for a bug report template or :? for other options.
CL-USER 90 : 1 > :C 1
LOL::ROTFL
10
In SBCL one can create the package via DEFPACKAGE and use the RETRY restart:
* (read-from-string "LOL::ROTFL")
debugger invoked on a SB-INT:SIMPLE-READER-PACKAGE-ERROR in thread
#<THREAD "main thread" RUNNING {10005184C3}>:
Package LOL does not exist.
Line: 1, Column: 9, File-Position: 9
Stream: #<SB-IMPL::STRING-INPUT-STREAM {1002F8ADF3}>
Type HELP for debugger help, or (SB-EXT:EXIT) to exit from SBCL.
restarts (invokable by number or by possibly-abbreviated name):
0: [CONTINUE ] Use the current package, COMMON-LISP-USER.
1: [RETRY ] Retry finding the package.
2: [USE-VALUE] Specify a different package
3: [UNINTERN ] Read the symbol as uninterned.
4: [SYMBOL ] Specify a symbol to return
5: [ABORT ] Exit debugger, returning to top level.
(SB-IMPL::READER-FIND-PACKAGE "LOL" #<SB-IMPL::STRING-INPUT-STREAM {1002F8ADF3}> T)
0] (defpackage "LOL")
#<PACKAGE "LOL">
0] 1
LOL::ROTFL
10
It's a convention, not an actual mechanism. But it's open to interpretations. What does ANIMATED-WINDOW-DRAW mean? Is it supposed to be WINDOW-DRAW in the ANIMATED 'package' or is it DRAW from the ANIMATED-WINDOW package? Probably there is another convention for that.
Note then that in Emacs Lisp the concept package means a software library, where in Common Lisp the concept package means a symbol namespace.
> Whereas in CL, isn’t the norm to use the package system everywhere?
It's widely used, but in slightly different ways. Some use it as a poor module system replacement. Often it is used a way to structure code into larger symbol namespaces. Sometimes you'll find code bases which do everything in one package.
> So you can’t just pass ‘foo-frobber to arbitrary packages and expect it to work.
'Passing to packages' is not a concept in Common Lisp. But you can use symbols from all packages everywhere. There is no enforced hiding mechanism or module system which hides things. The only thing packages actually do is being a namespace for symbols. Thus it is possible to have many symbols with the same name, but they need to be in different packages or need to belong to no package.
> For example, (intern “foo-frobber”) returns a symbol.
It does. It uses at runtime the package bound to the current package to intern the symbol.
The current package is the value of the symbol
> But can you just pass that plain old symbol between packages without having to explicitly indicate its origin?You can pass the symbol around. Its package can be queried. If you want to refer to the symbol in written code while being in another package (another symbol namespace) one has four options:
1) use the symbol fully qualified FOO::BAR. Note the two colons.
2) use exported symbols as FOO:BAR. Note the one colon.
3) use the symbol after importing it into the current package as BAR.
4) programmatically lookup the symbol: (find-symbol "BAR" "FOO")