From: Zach Beane on
Ron Garret <rNOSPAMon(a)flownet.com> writes:

> The other advantage of lexicons is that you don't have to manually
> maintain export lists. In addition to a parent, lexicons also have a
> list of "library" lexicons. The library lexicons are not searched
> recursively. So when you build a library now all you have to do it put
> all the public code in one lexicons, all the private code in a second
> lexicon which is in the first lexicon's library, and voila! All the
> public stuff is visible and all the private stuff is hidden. Lexicons
> let you stay DRY :-)

How does that work when you have a defclass form in a library lexicon
and you want the class name and some slot names visible, but other slot
names hidden?

Zach
From: Zach Beane on
Ron Garret <rNOSPAMon(a)flownet.com> writes:

> The more usual case (at least for me) is to load a whole
> bunch of code having forgotten to load the corresponding library. At
> that point it's not just one symbol that's potentially conflicting, it's
> a whole bunch of them. And shadowing-importing them all may or may not
> be the right thing to do. And in any case you then still have to reload
> all the client code.

As soon as I'm working on a project that depends on a library, I write
an ASDF system for it that loads the library before it loads my code. I
do this even if the project is a single file.

Even for scratch projects, the first thing I put in a file is a
defpackage form that uses CL and nothing else, and manually load
libraries as needed and use package prefixes. If I get sick of package
prefixes, I'll update the defpackage form and typically reach for
shadowing-import-from before use.

Zach
From: Tamas K Papp on
On Tue, 23 Feb 2010 09:38:52 -0500, Zach Beane wrote:

> Ron Garret <rNOSPAMon(a)flownet.com> writes:
>
>> The more usual case (at least for me) is to load a whole bunch of code
>> having forgotten to load the corresponding library. At that point it's
>> not just one symbol that's potentially conflicting, it's a whole bunch
>> of them. And shadowing-importing them all may or may not be the right
>> thing to do. And in any case you then still have to reload all the
>> client code.
>
> As soon as I'm working on a project that depends on a library, I write
> an ASDF system for it that loads the library before it loads my code. I
> do this even if the project is a single file.
>
> Even for scratch projects, the first thing I put in a file is a
> defpackage form that uses CL and nothing else, and manually load
> libraries as needed and use package prefixes. If I get sick of package
> prefixes, I'll update the defpackage form and typically reach for
> shadowing-import-from before use.

I am doing something similar. I found that short nicknames are rather
handy when I get tired of prefixes. I was wondering if it is "good
practice" to give nicknames to other's packages after the DEFPACKAGE
of my package, using RENAME-PACKAGE. Or should one just work with the
nicknames defined by the original author?

Tamas

From: Ron Garret on
In article <87mxz0qj5q.fsf(a)hangup.portland.xach.com>,
Zach Beane <xach(a)xach.com> wrote:

> Ron Garret <rNOSPAMon(a)flownet.com> writes:
>
> > The other advantage of lexicons is that you don't have to manually
> > maintain export lists. In addition to a parent, lexicons also have a
> > list of "library" lexicons. The library lexicons are not searched
> > recursively. So when you build a library now all you have to do it put
> > all the public code in one lexicons, all the private code in a second
> > lexicon which is in the first lexicon's library, and voila! All the
> > public stuff is visible and all the private stuff is hidden. Lexicons
> > let you stay DRY :-)
>
> How does that work when you have a defclass form in a library lexicon
> and you want the class name and some slot names visible, but other slot
> names hidden?
>
> Zach

As things currently stand you'd have to split the class up in to a
visible portion and a hidden portion that the visible portion inherits
from:

? (in-package :lexicons)
#<Package "LEXICONS">
? (in-lexicon :root)
#<Lexicon ROOT>
? (make-lexicon :lex1)
#<Lexicon LEX1>
? (make-lexicon :lex1-lib)
#<Lexicon LEX1-LIB>
? (in-lexicon :lex1-lib)
#<Lexicon LEX1-LIB>
? (ldefclass myclass-hidden () ((hidden-slot :initform :hidden)))
#<STANDARD-CLASS LEX1-LIB::MYCLASS-HIDDEN>
? (in-lexicon :lex1)
#<Lexicon LEX1>
? (use-lexicon :lex1-lib :lex1)
(#<Lexicon LEX1-LIB>)
? (ldefclass myclass (myclass-hidden) ((visible-slot :initform
:visible)))
#<STANDARD-CLASS LEX1::MYCLASS>
? (in-lexicon :root)
#<Lexicon ROOT>
? (use-lexicon :lex1)
(#<Lexicon LEX1>)
? (lmake-instance 'myclass)
#<LEX1::MYCLASS #x30200152CBCD>
? (ldefvar mc1 *)
#<LEX1::MYCLASS #x30200151D55D>
? (lslot-value mc1 'visible-slot)
:VISIBLE
? (lslot-value mc1 'hidden-slot)
; Warning: Deferring lexical binding of HIDDEN-SLOT
; While executing: REF-FORM, in process Listener(6).
Resolving binding of HIDDEN-SLOT
> Error: HIDDEN-SLOT is not bound in #<Lexicon ROOT>
> While executing: (:INTERNAL REF-FORM), in process Listener(6).
> Type cmd-. to abort, cmd-\ for a list of available restarts.
> Type :? for other options.
1 >

Note that you can always fall back on the underlying packages:

? (slot-value mc1 'lex1-lib::hidden-slot)
:HIDDEN

And of course:

? (in-lexicon :lex1-lib)
#<Lexicon LEX1-LIB>
? (lslot-value mc1 'hidden-slot)
:HIDDEN

If you find having to use inheritance to hide slots to be intolerably
annoying, it would be straightforward to extend ldefclass so that you
could hide slots directly. Personally I think having to separate the
visible and hidden parts this way is good engineering discipline.

Two notes:

1. The version of lexicons I pushed out yesterday had a bug in
lslot-value so if you want this to work you'll need to snarf the code
again.

2. Lexicons do not currently separate slot names into a separate
namespace. So you can shadow a slot name in a library with, e.g. a
function name or a variable in the client lexicon, i.e.:

? (in-lexicon :root)
#<Lexicon ROOT>
? (lslot-value mc1 'visible-slot)
:VISIBLE
? (ldefvar visible-slot 'this-will-cause-breakage)
THIS-WILL-CAUSE-BREAKAGE
? (lslot-value mc1 'visible-slot)
> Error: #<LEX1::MYCLASS #x30200151D55D> has no slot named ROOT::VISIBLE-SLOT.

This would be a little harder to fix, but not impossible, and I'd be
happy to fix it if there's demand.

rg
From: Ron Garret on
In article <87r5ocqkaf.fsf(a)hangup.portland.xach.com>,
Zach Beane <xach(a)xach.com> wrote:

> Ron Garret <rNOSPAMon(a)flownet.com> writes:
>
> > In article <87y6ikraw1.fsf(a)hangup.portland.xach.com>,
> > Zach Beane <xach(a)xach.com> wrote:
> >
> >> Ron Garret <rNOSPAMon(a)flownet.com> writes:
> >>
> >> > Feedback welcome.
> >>
> >> How does this interact with cl-ppcre's compiler macro for SCAN?
> >>
> >> Zach
> >
> > It should have no effect. The way lexicons work (now -- it was very
> > different before) is that all symbols in the lexicons package get
> > "lexified", which means that they get both a regular macro and a symbol
> > macro defined for them whose expansion is simply to replace the symbol
> > with the symbol of the same name in the lexicon's package. So
> > (lexicons::scan ...) is a macro that expands to (cl-ppcre:scan ...). So
> > any compiler macro defined on cl-ppcre:scan should Just Work.
>
> When does the compiler macro get expanded in the example on your blog?
> Is that "Resolving binding..." a message indicating recompilation of
> FOO?
>
> Zach

Ah.

No, when you resolve a lexical binding at run-time you lose the effect
of compiler macros. You get them back again if you recompile the
original definition. Run-time binding resolution is intended to make
development easier, not to provide optimal performance. Here's an
example. I've instrumented the compiler macro to make noise when it
runs:

? (in-package :cl-user)
#<Package "COMMON-LISP-USER">
? (defun foo () (scan "(a)*b" "xaaabd"))

INVOKING-SCAN-COMPILER-MACRO
INVOKING-SCAN-COMPILER-MACRO
FOO
? (in-package :lexicons)
#<Package "LEXICONS">
? (defun foo () (scan "(a)*b" "xaaabd"))
;Compiler warnings :
; In FOO: Deferring lexical binding of SCAN
FOO
? (lexify-package :cl-ppcre)
#<Lexicon CL-PPCRE>
? (use-lexicon :cl-ppcre)
(#<Lexicon CL-PPCRE> #<Lexicon LEX1>)
? (foo)
Resolving binding of SCAN
1
5
#(3)
#(4)
? (defun foo () (scan "(a)*b" "xaaabd"))

CL-PPCRE::INVOKING-SCAN-COMPILER-MACRO
CL-PPCRE::INVOKING-SCAN-COMPILER-MACRO
FOO



The way deferred binding works is this: every lexical reference is run
through a lookup procedure called REF-FORM, which returns a FORM that,
when invoked, returns the binding. If the binding can be resolved at
compile-time then the form returns is simply '(QUOTE BINDING) where
BINDING is the binding that is lexically visible at macroexpansion time.
If there is no lexically visible binding, then REF-FORM returns the
following:

(FUNCALL #<COMPILED-LEXICAL-CLOSURE (:INTERNAL REF-FORM)
#x302001C7FFBF>)))

Where the closure re-does the lexical lookup and caches the result if it
finds one.

Lexical functions (which are actually macros) examine the structure of
this form at compile time. If it starts with the symbol QUOTE then the
macro expands simply into BINDING, which is a symbol in this new
implementation. If it's not QUOTE then it's a deferred binding and the
call expands into:

(funcall (symbol-function [the-ref-form]))

(I think the call to SYMBOL-FUNCTION could actually be removed and it
would still work.)

So using a runtime-resolved binding is slightly less efficient, but you
get it all back the next time you recompile the client. Here's an
example:


? (defun foo () (baz))
;Compiler warnings :
; In FOO: Deferring lexical binding of BAZ
FOO
? (macroexpand '(baz))
; Warning: Deferring lexical binding of BAZ
; While executing: REF-FORM, in process Listener-2(7).
(FUNCALL (SYMBOL-FUNCTION (FUNCALL #<COMPILED-LEXICAL-CLOSURE (:INTERNAL
REF-FORM) #x302001C7FFBF>)))
T
? (setf form *)
(FUNCALL (SYMBOL-FUNCTION (FUNCALL #<COMPILED-LEXICAL-CLOSURE (:INTERNAL
REF-FORM) #x302001C30C0F>)))
? (ldefun baz () :baz) ; Note that this is LDEFUN, not DEFUN
ROOT::BAZ
? (eval form)
Resolving binding of BAZ
:BAZ
? (macroexpand '(baz))
(ROOT::BAZ)
T