From: Eric Dahlman
Subject: Implementing in-package like semantics
Date: 
Message-ID: <tz4y93hyh73.fsf@flatt.cs.colostate.edu>
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
From: Kalle Olavi Niemitalo
Subject: Re: Implementing in-package like semantics
Date: 
Message-ID: <87llzh572a.fsf@Astalo.kon.iki.fi>
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