Howdy,
I need to implement something very much like in-package and I was
wondering if anybody had an idea of how I could get a 100% solution.
Basically, I want to make a form (in-foo :bar) which can be in the
top-level of a lisp file and will itself expand into something like
(setf *squirreled-away-foo* *global-foo*)
(setf *global-foo* :bar)
The kicker is that then I want to have something equivalent to (setf
*global-foo* *squirreled-away-foo*) happen at the end of the file.
Yes, it needs to handle multiple in-foos in one file but for
reasons of simplicity lets assume that is not the case.
I have looked at two basic solutions both of which don't really float
my boat. One option is to record the file name being loaded at the
point of the in-foo form and then when using that global checking to
see if the current file matches, if not I revert the value. This just
feels crufty and it does not interact with Emacs and C-M-x very well.
The other solution is to use defadvice to wrap load with a let form to
automatically revert the value after load returns. This is
problematic since defadvice is not very standard.
I am just going to assume that whatever solution I find it won't play
nicely with C-M-x since there is no way for Emacs to know about my
added context. But is there a third way I have not seen that would be
better?
Thanks a bunch,
-Eric
From: Tim Bradshaw
Subject: Re: Implementing in-package like semantics
Date:
Message-ID: <ey3n0jxvd6u.fsf@cley.com>
* Eric Dahlman wrote:
> The other solution is to use defadvice to wrap load with a let form to
> automatically revert the value after load returns. This is
> problematic since defadvice is not very standard.
I can't think of a way that isn't something like this. I think I'd do
it by defining a CL-like package where LOAD (&c) were functions that
did something like:
(defvar *load-rebinds* '(...))
(defun load (&rest args)
(progv
*load-rebinds*
*load-rebinds*
(apply #'cl:load args)))
and then have the IN-x form just assign to some suitable rebound
variable. You need to deal with COMPILE-FILE too, especially if you
want the IN-x to do things at compile time.
(Obviously you need to make sure that you use this Cl-like package
instead of CL, and train emacs &co to use your LOAD).
> I am just going to assume that whatever solution I find it won't play
> nicely with C-M-x since there is no way for Emacs to know about my
> added context. But is there a third way I have not seen that would be
> better?
Well, presumably you could generalise whatever code emacs has to
detect IN-PACKAGE & deal with it...
--tim
Tim Bradshaw <ยทยทยท@cley.com> writes:
> (defun load (&rest args)
> (progv
> *load-rebinds*
> *load-rebinds*
> (apply #'cl:load args)))
That would bind the variables to their own names.
(defun load (&rest args)
(progv
*load-rebinds*
(mapcar #'symbol-value *load-rebinds*)
(apply #'cl:load args)))
Or even:
(defun load (&rest args)
(let ((bound-symbols (remove-if-not #'boundp *load-rebinds*))
(unbound-symbols (remove-if #'boundp *load-rebinds*)))
(progv bound-symbols (mapcar #'symbol-value bound-symbols)
(progv unbound-symbols '()
(apply #'cl:load args)))))
Should there be any difference between that and:
(defun load (&rest args)
(let ((bound-symbols (remove-if-not #'boundp *load-rebinds*))
(unbound-symbols (remove-if #'boundp *load-rebinds*)))
(progv
(append bound-symbols unbound-symbols)
(mapcar #'symbol-value bound-symbols)
(apply #'cl:load args))))
? I am not too fluent with PROGV.
From: Tim Bradshaw
Subject: Re: Implementing in-package like semantics
Date:
Message-ID: <ey3wuj0peio.fsf@cley.com>
* Kalle Olavi Niemitalo wrote:
> That would bind the variables to their own names.
Oops, yes.
> (defun load (&rest args)
> (let ((bound-symbols (remove-if-not #'boundp *load-rebinds*))
> (unbound-symbols (remove-if #'boundp *load-rebinds*)))
> (progv bound-symbols (mapcar #'symbol-value bound-symbols)
> (progv unbound-symbols '()
> (apply #'cl:load args)))))
I think this would be OK:
(defun load (&rest args)
(progv
*bound-symbols*
(mapcar #'(lambda (s)
(if (boundp s) (symbol-value s) nil)))
(apply #'cl:load args)))
But I think I'd prefer to say that it is an error for these things not
to be bound (like, say *PACKAGE*, or something, where it would be very
weird for it not to be bound).
--tim