From: Adam Warner
Subject: 3.4.1.3: &rest may share structure with the last argument to apply
Date: 
Message-ID: <pan.2005.05.14.23.08.05.746960@consulting.net.nz>
Hi all,

3.4.1.3 "A specifier for a rest parameter" of the HyperSpec states "The
value of a rest parameter is permitted, but not required, to share
structure with the last argument to apply."

I'm building some new calling functionality and I regrettably have to cons
up a rest list to decode the arguments. Sometimes I will be able to avoid
this cost at run time using compiler macros. When I can't I wish to mutate
the rest list to avoid further expensive copying.

I'm hoping to predicate the code generated to decode function arguments
upon whether an implementation actually shares structure with the last
argument to apply. If it shares structure I will have to insert a call to
COPY-LIST before mutating a copy of any rest list.

Does anyone know of an implementation that shares this structure under any
circumstances? Is this code likely to detect such as implementation or can
a more accurate test be devised:

(declaim (optimize (safety 0) (speed 3)))

(defparameter *last-argument-to-apply* '(1 2 3))

(defun test-for-shared-structure (&rest args)
  (when (eq args '#.*last-argument-to-apply*)
    (print "Rest parameter shares structure with the last argument to apply")))

(apply #'test-for-shared-structure '#.*last-argument-to-apply*)

Thanks,
Adam

From: Adam Warner
Subject: Re: 3.4.1.3: &rest may share structure with the last argument to apply
Date: 
Message-ID: <pan.2005.05.15.01.54.13.927005@consulting.net.nz>
On Sun, 15 May 2005 11:08:07 +1200, Adam Warner wrote:
> Does anyone know of an implementation that shares [a rest parameter with
> the last argument to apply] under any circumstances? Is this code
> likely to detect such as implementation or can a more accurate test be
> devised:

The test code I'm comfortable with is posted below. I carefully detect
whether structure is shared in multiple evaluation environments for an
identical list and any inconsistent result aborts (an #+implementation
specific condition should then be added).

(eval-when (:compile-toplevel :load-toplevel :execute)
  (defconstant |rest-shares-structure-with-last-argument-to-apply|
    (locally
        ;;Implementation likelier to share structure at highest optimisation?
        (declare (optimize (compilation-speed 0) (debug 0) (safety 0) speed))
      (let ((test-for-shared-structure
             (lambda (list &rest args)
               (unless (cl:equal list args)
                 (error "Ensure test arguments to apply are equal"))
               (cl:eq list args))))
        (let* ((test-list '(1 2 3))
               (shared-result (apply test-for-shared-structure
                                     test-list test-list)))
          (if (boundp '|rest-shares-structure-with-last-argument-to-apply|)
              (if (eq (symbol-value
                       '|rest-shares-structure-with-last-argument-to-apply|)
                      shared-result)
                  shared-result
                  (error "Test for rest parameter sharing structure with list argument to apply was inconsistent between evaluation environments. Set always true for this implementation."))
              shared-result))))))

Regards,
Adam
From: Adam Warner
Subject: Re: 3.4.1.3: &rest may share structure with the last argument to apply
Date: 
Message-ID: <pan.2005.05.15.02.11.19.202155@consulting.net.nz>
On Sun, 15 May 2005 13:54:17 +1200, Adam Warner wrote:
> The test code I'm comfortable with is posted below. I carefully detect
> whether structure is shared in multiple evaluation environments for an
> identical list and any inconsistent result aborts (an #+implementation
> specific condition should then be added).

Update: This code detects that CLISP sometimes shares structure with the
last argument to apply. In the compilation environment/while compiling the
code shared structure was not detected. Upon loading the resulting fas
file structure was shared and the error condition invoked. For CLISP the
share structure constant should be unconditionally T.

Regards,
Adam
From: Pascal Bourguignon
Subject: Re: 3.4.1.3: &rest may share structure with the last argument to apply
Date: 
Message-ID: <874qd44dtl.fsf@thalassa.informatimago.com>
Adam Warner <······@consulting.net.nz> writes:
> 3.4.1.3 "A specifier for a rest parameter" of the HyperSpec states "The
> value of a rest parameter is permitted, but not required, to share
> structure with the last argument to apply."
>
> I'm building some new calling functionality and I regrettably have to cons
> up a rest list to decode the arguments. 

You are surprizing me.
In my mind, "building new calling functionality" would be done with macros.

Macros can avoid any run-time consing: instead of using APPLY or even
FUNCALL, you can write the function calling s-expression:


(defun implement-some-macro-expansion-time-functionality (func arguments)
   (format t "~&me-time functionality ~A with ~S~%" func arguments))

(defun macro-expansion-time-function-massaging (func arguments)
   (format t "~&me-time function massaging  ~A with ~S~%" func arguments)
   (let ((argnames (mapcar (lambda (arg) (gensym)) arguments)))
   func))
   
(defun macro-expansion-time-argument-massaging (func arguments)
   (format t "~&me-time argument massaging  ~A with ~S~%" func arguments)
   (flet ((massage (arg)  arg))
       (mapcar (lambda (arg) (massage arg)) arguments)))
       

(defmacro some-new-calling-functionality (func &rest arguments)
   (implement-some-macro-expansion-time-functionality func arguments)
   `(progn
      (implement-some-run-time-functionality (function ,func) 
           ',arguments #| or handle one time evaluation of arguments. |#)
      (,(macro-expansion-time-function-massaging func arguments)
          ,@(macro-expansion-time-argument-massaging func arguments))))



[45]> (macroexpand-1 '(some-new-calling-functionality 
                            concatenate 'string "Hello" " " "World"))
me-time functionality CONCATENATE with ('STRING "Hello" " " "World")
me-time function massaging  CONCATENATE with ('STRING "Hello" " " "World")
me-time argument massaging  CONCATENATE with ('STRING "Hello" " " "World")
(PROGN
 (IMPLEMENT-SOME-RUN-TIME-FUNCTIONALITY #'CONCATENATE
  '('STRING "Hello" " " "World"))
 (CONCATENATE 'STRING "Hello" " " "World")) ;
T


-- 
__Pascal Bourguignon__                     http://www.informatimago.com/
Small brave carnivores
Kill pine cones and mosquitoes
Fear vacuum cleaner