Prev: [CfP] 2nd International Workshop on Context-oriented Programming
Next: google "go" vs common lisp
From: Zach Beane on 23 Feb 2010 06:35 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 23 Feb 2010 09:38 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 23 Feb 2010 10:22 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 23 Feb 2010 12:09 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 23 Feb 2010 12:36 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
First
|
Prev
|
Next
|
Last
Pages: 1 2 3 Prev: [CfP] 2nd International Workshop on Context-oriented Programming Next: google "go" vs common lisp |