From: Chaitanya Gupta
Subject: PROGV question
Date: 
Message-ID: <f56d33$mlb$1@registered.motzarella.org>
How should PROGV behave when, in the list of symbols to be bound, a
symbol is repeated twice? e.g. I get this for both ACL and SBCL -

(progv '(*x *x) '(2 3)
  (symbol-value '*x))
=>
3

From the hyperspec[1], its not clear (atleast to me!) whether this
behaviour is gauranteed. Can I rely on the above result as standard
behaviour for PROGV?

Thanks,

Chaitanya

Notes -
1. http://www.lispworks.com/documentation/HyperSpec/Body/s_progv.htm#progv

From: Pillsy
Subject: Re: PROGV question
Date: 
Message-ID: <1182188249.428312.207960@q75g2000hsh.googlegroups.com>
On Jun 18, 12:49 pm, Chaitanya Gupta <····@chaitanyagupta.com> wrote:

> How should PROGV behave when, in the list of symbols to be bound, a
> symbol is repeated twice? e.g. I get this for both ACL and SBCL -

> (progv '(*x *x) '(2 3)
>   (symbol-value '*x))
> =>
> 3

LispWorks and CLisp also return 3.

> From the hyperspec[1], its not clear (atleast to me!) whether this
> behaviour is gauranteed.

I interpret the "evaluated in order" language in the spec to mean that
the behavior is guaranteed, but I could be wrong.

Cheers,
Pillsy
From: Kent M Pitman
Subject: Re: PROGV question
Date: 
Message-ID: <uwsy0ewee.fsf@nhplace.com>
Pillsy <·········@gmail.com> writes:

> On Jun 18, 12:49 pm, Chaitanya Gupta <····@chaitanyagupta.com> wrote:
> 
> > How should PROGV behave when, in the list of symbols to be bound, a
> > symbol is repeated twice? e.g. I get this for both ACL and SBCL -
> 
> > (progv '(*x *x) '(2 3)
> >   (symbol-value '*x))
> > =>
> > 3
> 
> LispWorks and CLisp also return 3.
> 
> > From the hyperspec[1], its not clear (atleast to me!) whether this
> > behaviour is gauranteed.
> 
> I interpret the "evaluated in order" language in the spec to mean that
> the behavior is guaranteed, but I could be wrong.

Yeah, it's probably not well-defined, which probably means it wasn't
well-defined under CLTL and earlier specs either.

If you're a pragmatist: The most likely implementations will be to
either push all the locations and then push all the values, or to push
a location then set the location in interleaved fashion.  The
likelihood of someone returning 2 there is pretty low, IMO.  So you
could do something at toplevel like:

 (eval-when (:compile-toplevel)
   (unless (eql (ignore-errors (progv '(*x *x) '(2 3) 
                                 (symbol-value '*x)))
                3)
     (error "Assumption about *progv violated.  Need to recode.")))

Or you could ask each vendor if it's reliable and then instead of checking
at load time you could do:

 #+(or vendor-a-who-says-it-is-ok vendor-b-who-says-it-is-ok)
 (... do what you want ...)
 #-(or vendor-a-who-says-it-is-ok vendor-b-who-says-it-is-ok)
 (error "need an implementation")

Or, you could, of course, write the obvious progv* that turned into a
cascade of progv's, and then it would be well-defined what happens.

But ... 

Is it out of bounds to ask why this issue comes up and whether there
might not be another answer?  Like, for example, "don't allow the 
situation to arise in the first place"?  That's often the most elegant
answer for things like this.
From: Chaitanya Gupta
Subject: Re: PROGV question
Date: 
Message-ID: <f5ag3h$h3k$1@registered.motzarella.org>
Kent M Pitman wrote:

> 
> Is it out of bounds to ask why this issue comes up and whether there
> might not be another answer?  Like, for example, "don't allow the 
> situation to arise in the first place"?  That's often the most elegant
> answer for things like this.

Yes. That's probably the right thing to do. I will write what I had in
mind, and how this issue might have come up -

Say you want to create a new process and establish some dynamics
bindings for it from the parent process. So I have something like this -

(defvar *process-inherited-bindings* nil)


(defun call-with-bindings (function args &key process-bindings)
  "Binds *PROCESS-INHERITED-BINDINGS* to the value of PROCESS-BINDINGS,
creates dynamic bindings from this value, and calls the FUNCTION with
ARGS inside these bindings."
  (let ((*process-inherited-bindings* process-bindings))
    (progv (mapcar #'car process-bindings)
	(mapcar #'cdr process-bindings)
      (multiple-value-list (apply function args)))))


So I can create a new process like this -

;; Using ACL's process-run-function
(mp:process-run-function "some process"
			 #'(lambda (bindings)
			     (call-with-bindings function args :process-bindings bindings))
			 '((*x . 1)
			   (*y . 2)))

The purpose of *process-inherited-bindings* is that the new process may
create another child process, and would want this new process to inherit
its bindings. i.e. inside "some process"

(mp:process-run-function "some new process"
			 #'(lambda (bindings)
			     (call-with-bindings function args :process-bindings bindings))
			 *process-inherited-bindings*)

Everything is fine uptil now, but say that "some process" wants *x for
"some new process" to be different from what it inherited, and leave all
the other inherited bindings intact. So what I wanted to know was
whether I could rely on this -

(mp:process-run-function "some new process"
			 #'(lambda (bindings)
			     (call-with-bindings function args :process-bindings bindings))
			 (cons '(*x . 2) *process-inherited-bindings*))

or this -

(mp:process-run-function "some new process"
			 #'(lambda (bindings)
			     (call-with-bindings function args :process-bindings bindings))
			 (append *process-inherited-bindings* '((*x . 2))))


Or whether I should always do something like this -

(mp:process-run-function "some new process"
			 #'(lambda (bindings)
			     (call-with-bindings function args :process-bindings bindings))
			 (remove-duplicate-bindings '((*x . 2)) *process-inherited-bindings*))


I think I have my answer now. Or is there a better way still?


(On a side note: I wanted to do this for ACL, because I didn't think it
had something like *process-inherited-bindings*. But going throught the
docs again, I found that it does give the initial bindings for a process
using mp:process-initial-bindings (provided you create them using
process-run-function's binding mechanism). So I won't really be using
this now, but it might be useful in SBCL, which AFAIK doesn't give you
the initial bindings for a process.)

Chaitanya
From: Kent M Pitman
Subject: Re: PROGV question
Date: 
Message-ID: <uy7ifku7z.fsf@nhplace.com>
Chaitanya Gupta <····@chaitanyagupta.com> writes:

> Or whether I should always do something like this -
> 
> (mp:process-run-function "some new process"
> 			 #'(lambda (bindings)
> 			     (call-with-bindings function args :process-bindings bindings))
> 			 (remove-duplicate-bindings '((*x . 2)) *process-inherited-bindings*))
> 

Perhaps

 (defun call-with-bindings (function &optional bindings inherited-bindings)
   (progw inherited-bindings
     (progw bindings
       (funcall function))))

for a suitably defined PROGW.  That is, you don't really need to
remove duplicates, you could just cascade it in two calls and
would probably be fine.

I think the Lisp Machine had progw.  I don't have a manual handy, so I
could not tell you for sure, but I suspect it took a list-style (rather
than cons-style alist), so it looked like a binding list.  I don't recall
if it evaluated the value part, but probably not.  That is, it was 
probably
  (progw bindings (f))
  ==>
  (let ((temp bindings))
    (progv (mapcar #'first  temp)
           (mapcar #'second temp)
      (f)))
but maybe someone with a Chinual or some such document handy can answer.

The reason I like this is that it reflects the structure of your programs.

> I think I have my answer now. Or is there a better way still?

It's all fairly subjective.  It's always good to have options.
From: Chaitanya Gupta
Subject: Re: PROGV question
Date: 
Message-ID: <f5as24$8o4$1@registered.motzarella.org>
Kent M Pitman wrote:
> Chaitanya Gupta <····@chaitanyagupta.com> writes:
> 
>> Or whether I should always do something like this -
>>
>> (mp:process-run-function "some new process"
>> 			 #'(lambda (bindings)
>> 			     (call-with-bindings function args :process-bindings bindings))
>> 			 (remove-duplicate-bindings '((*x . 2)) *process-inherited-bindings*))
>>
> 
> Perhaps
> 
>  (defun call-with-bindings (function &optional bindings inherited-bindings)
>    (progw inherited-bindings
>      (progw bindings
>        (funcall function))))
> 
> for a suitably defined PROGW.  That is, you don't really need to
> remove duplicates, you could just cascade it in two calls and
> would probably be fine.
> 

Hmm.. Cascading progv/w(s). Didn't really think about it (even though
you mentioned it in your previous post). This should work very nicely.

> 
> It's all fairly subjective.  It's always good to have options.

I'll agree. Though sometimes too many options confuse me, its still
better than no options. ;)

Chaitanya
From: Rob Warnock
Subject: Re: PROGV question
Date: 
Message-ID: <DtSdnQ-Hk8-wvuTbnZ2dnUVZ_s_inZ2d@speakeasy.net>
Chaitanya Gupta  <····@chaitanyagupta.com> wrote:
+---------------
| (On a side note: I wanted to do this for ACL, because I didn't think it
| had something like *process-inherited-bindings*. But going throught the
| docs again, I found that it does give the initial bindings for a process
| using mp:process-initial-bindings (provided you create them using
| process-run-function's binding mechanism). So I won't really be using
| this now, but it might be useful in SBCL, which AFAIK doesn't give you
| the initial bindings for a process.)
+---------------

If they haven't changed SBCL's MP package *too* much from what
they inherited from CMUCL, there should be an :INITIAL-BINDINGS
keyword in the MP:MAKE-PROCESS function:

  :INITIAL-BINDINGS
        An alist of initial special bindings for the process.  At
        startup the new process has a fresh set of special bindings
        with a default binding of *package* setup to the CL-USER
        package.  INITIAL-BINDINGS specifies additional bindings for
        the process.  The cdr of each alist element is evaluated in
        the fresh dynamic environment and then bound to the car of the
        element.


-Rob

-----
Rob Warnock			<····@rpw3.org>
627 26th Avenue			<URL:http://rpw3.org/>
San Mateo, CA 94403		(650)572-2607
From: Pascal Costanza
Subject: Re: PROGV question
Date: 
Message-ID: <5ds1qeF35gk7gU1@mid.individual.net>
Chaitanya Gupta wrote:

> Or whether I should always do something like this -
> 
> (mp:process-run-function "some new process"
> 			 #'(lambda (bindings)
> 			     (call-with-bindings function args :process-bindings bindings))
> 			 (remove-duplicate-bindings '((*x . 2)) *process-inherited-bindings*))
> 
> 
> I think I have my answer now. Or is there a better way still?

(cons '(*x . 2) (remove '*x *process-inherited-bindings* :key #'car))

Also possible:

(defun call-with-bindings (function args &key process-bindings)
   (if process-bindings
      (progv (list (caar process-bindings))
             (list (cdar process-bindings))
        (call-with-bindings function args
          :process-bindings (cdr process-bindings)))
      (apply function args)))

...but if *process-inherited-bindings* is a long list, this may cons too 
much.


Pascal

-- 
My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
From: Chaitanya Gupta
Subject: Re: PROGV question
Date: 
Message-ID: <f5at7h$bik$1@registered.motzarella.org>
Pascal Costanza wrote:
> Chaitanya Gupta wrote:
> 
>> Or whether I should always do something like this -
>>
>> (mp:process-run-function "some new process"
>>              #'(lambda (bindings)
>>                  (call-with-bindings function args :process-bindings
>> bindings))
>>              (remove-duplicate-bindings '((*x . 2))
>> *process-inherited-bindings*))
>>
>>
>> I think I have my answer now. Or is there a better way still?
> 
> (cons '(*x . 2) (remove '*x *process-inherited-bindings* :key #'car))

remove-duplicate-bindings would do this (and more) -

(defun remove-duplicate-bindings (bindings inherited-bindings)
  (append (set-difference inherited-bindings bindings :key #'car) bindings))


> 
> Also possible:
> 
> (defun call-with-bindings (function args &key process-bindings)
>   (if process-bindings
>      (progv (list (caar process-bindings))
>             (list (cdar process-bindings))
>        (call-with-bindings function args
>          :process-bindings (cdr process-bindings)))
>      (apply function args)))
> 

That's also quite good.

Thanks,

Chaitanya
From: Pascal Costanza
Subject: Re: PROGV question
Date: 
Message-ID: <5do2nuF35rod8U1@mid.individual.net>
Chaitanya Gupta wrote:
> How should PROGV behave when, in the list of symbols to be bound, a
> symbol is repeated twice? e.g. I get this for both ACL and SBCL -
> 
> (progv '(*x *x) '(2 3)
>   (symbol-value '*x))
> =>
> 3
> 
> From the hyperspec[1], its not clear (atleast to me!) whether this
> behaviour is gauranteed. Can I rely on the above result as standard
> behaviour for PROGV?

No, it's simply not specified. (It's also not specified for let, lambda 
and other binding forms.)

You have to preprocess the lists to ensure reliable behavior.


Pascal

-- 
My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
From: Vassil Nikolov
Subject: Re: PROGV question
Date: 
Message-ID: <kamyyw7f2x.fsf@localhost.localdomain>
On Mon, 18 Jun 2007 20:54:54 +0200, Pascal Costanza <··@p-cos.net> said:

| Chaitanya Gupta wrote:
|| How should PROGV behave when, in the list of symbols to be bound, a
|| symbol is repeated twice?
|| ...
| No, it's simply not specified. (It's also not specified for let,
| lambda and other binding forms.)

  I. Hmmm...  Which of the two options below is the right one?

  I.1. Error.

  In the HyperSpec, 3.1.1 Introduction to Environments [1] says:

    A single name can simultaneously have more than one associated
    binding per environment, but can have only one associated binding
    per namespace.

  Doesn't that mean that duplicating a variable is not allowed?  (Or
  am I reading more into it than it says?  Or is it ambiguous?)

  So, in I.1. I believe that duplicate symbols in the value of PROGV's
  first subform (should be construed to) have undefined consequences.

  I.2. Rightmost occurrence prevails.

  This is based on the traditional interpretation of <lambda>xy.E as
  <lambda>x.<lambda>y.E (which makes <lambda>xx.E well-defined, though
  perhaps not very interestingly so).

  This seems to be upheld by the following fragment from CLtL (Chapter
  3, p. 38, 3rd paragraph):

    If two entities have the same name, then the second may shadow the
    first, in which case an occurrence of the name will refer to the
    second and cannot refer to the first.

  Again, I am not really sure if the above applies to the case at
  hand, especially given the presence of "may".  I could not find a
  corresponding fragment in the HyperSpec.


  II. More trouble.

  For consistency's sake (at least), variable binding and function
  binding should work along the same lines in the case of duplicated
  names.  However...

     * (defun foo () (flet ((bar () 'bar1) (bar () 'bar2)) (bar)))
    FOO
     * (foo)
    BAR2  ;so far, so good (?)
     * (compile 'foo)
    FOO ;
    NIL ;
    NIL
     * (foo)
    BAR1  ;hmmm...

  (this is with CLisp 2.41, but that's just because that is what I
  happen to have at hand right now).  Is the above in error, or is it
  all right since everything is all right when the consequences are
  undefined?


  [1] http://www.lisp.org/HyperSpec/Body/sec_3-1-1.html

  ---Vassil,
  perplexed...


-- 
The truly good code is the obviously correct code.
From: Rob Warnock
Subject: Re: PROGV question
Date: 
Message-ID: <FYidnaOBWtauJ-rbnZ2dnUVZ_vvinZ2d@speakeasy.net>
Vassil Nikolov  <···············@pobox.com> wrote:
+---------------
|      * (defun foo () (flet ((bar () 'bar1) (bar () 'bar2)) (bar)))
|     FOO
|      * (foo)
|     BAR2  ;so far, so good (?)
|      * (compile 'foo)
|     FOO ;
|     NIL ;
|     NIL
|      * 
+---------------

CMUCL isn't silent in this case:

    cmu> (compile 'foo)

    ; Note: Deleting unused function
    ;   (FLET BAR
    ;     FOO)
    ; 
    ; Compiling LAMBDA NIL: 
    ; Compiling Top-Level Form: 

    ; Compilation unit finished.
    ;   1 note


    FOO
    T
    NIL
    cmu> (foo))

    BAR2
    cmu> 

Doesn't mean it's "right", though...


-Rob

-----
Rob Warnock			<····@rpw3.org>
627 26th Avenue			<URL:http://rpw3.org/>
San Mateo, CA 94403		(650)572-2607
From: Chaitanya Gupta
Subject: Re: PROGV question
Date: 
Message-ID: <f5agf7$hbe$1@registered.motzarella.org>
Vassil Nikolov wrote:
> On Mon, 18 Jun 2007 20:54:54 +0200, Pascal Costanza <··@p-cos.net> said:
> 
> | Chaitanya Gupta wrote:
> || How should PROGV behave when, in the list of symbols to be bound, a
> || symbol is repeated twice?
> || ...
> | No, it's simply not specified. (It's also not specified for let,
> | lambda and other binding forms.)
> 
>   I. Hmmm...  Which of the two options below is the right one?
> 
>   I.1. Error.
> 
>   In the HyperSpec, 3.1.1 Introduction to Environments [1] says:
> 
>     A single name can simultaneously have more than one associated
>     binding per environment, but can have only one associated binding
>     per namespace.
> 
>   Doesn't that mean that duplicating a variable is not allowed?  (Or
>   am I reading more into it than it says?  Or is it ambiguous?)
> 
>   So, in I.1. I believe that duplicate symbols in the value of PROGV's
>   first subform (should be construed to) have undefined consequences.
> 
>   I.2. Rightmost occurrence prevails.
> 
>   This is based on the traditional interpretation of <lambda>xy.E as
>   <lambda>x.<lambda>y.E (which makes <lambda>xx.E well-defined, though
>   perhaps not very interestingly so).
> 
>   This seems to be upheld by the following fragment from CLtL (Chapter
>   3, p. 38, 3rd paragraph):
> 
>     If two entities have the same name, then the second may shadow the
>     first, in which case an occurrence of the name will refer to the
>     second and cannot refer to the first.
> 
>   Again, I am not really sure if the above applies to the case at
>   hand, especially given the presence of "may".  I could not find a
>   corresponding fragment in the HyperSpec.
> 
> 
>   II. More trouble.
> 
>   For consistency's sake (at least), variable binding and function
>   binding should work along the same lines in the case of duplicated
>   names.  However...
> 
>      * (defun foo () (flet ((bar () 'bar1) (bar () 'bar2)) (bar)))
>     FOO
>      * (foo)
>     BAR2  ;so far, so good (?)
>      * (compile 'foo)
>     FOO ;
>     NIL ;
>     NIL
>      * (foo)
>     BAR1  ;hmmm...

More confusion. But very interesting. Thanks for pointing these out.

Chaitanya