From: Tamas K Papp
Subject: serialization of functions/closures
Date: 
Message-ID: <6s46m9F3vmasU1@mid.individual.net>
Hi,

I am looking for a serialization library that would also serialize 
closures/functions.  Is this possible at all?  The cliki page for cl-
store says "Hopefully one day proper functions and closures will be 
added."  How can one do that?

Thanks,

Tamas

From: Volkan YAZICI
Subject: Re: serialization of functions/closures
Date: 
Message-ID: <6ac3f855-185f-47b6-b2ae-fab31df3b8c4@w39g2000prb.googlegroups.com>
On Jan 1, 5:44 pm, Tamas K Papp <······@gmail.com> wrote:
> I am looking for a serialization library that would also serialize
> closures/functions.  Is this possible at all?  The cliki page for cl-
> store says "Hopefully one day proper functions and closures will be
> added."  How can one do that?

You can search c.l.l archives using "serialize" and "closure" keywords
for various discussions about the subject.


Regards.
From: Stanisław Halik
Subject: Re: serialization of functions/closures
Date: 
Message-ID: <gjis73$1gcn$1@opal.icpnet.pl>
thus spoke Tamas K Papp <······@gmail.com>:

> Hi,
> I am looking for a serialization library that would also serialize 
> closures/functions.

SB-HEAPDUMP.

-- 
You only have power over people so long as you don’t take everything
away from them. But when you’ve robbed a man of everything he’s no longer
in your power — he’s free again. -- Aleksandr Isayevich Solzhenitsyn
From: Pascal Costanza
Subject: Re: serialization of functions/closures
Date: 
Message-ID: <6s4mt3F48p9eU1@mid.individual.net>
Tamas K Papp wrote:
> Hi,
> 
> I am looking for a serialization library that would also serialize 
> closures/functions.  Is this possible at all?  The cliki page for cl-
> store says "Hopefully one day proper functions and closures will be 
> added."  How can one do that?

Closures are hard: When serialized to another location, do you want to 
see the same bindings as the original closure? Do you want to ensure 
that side effects on the bindings are signaled back to the original 
location? Should side effects from the original location always be 
propagated to the new location?

Functions that don't close over anything are easy. Here is a sketch that 
we used in some project:

(in-package :closer-common-lisp-user)

(defgeneric update-instance-after-reading (object)
   (:method ((object t)) object))

(defclass value-object () ())

(defun value-object (class-name &rest initargs)
   (declare (dynamic-extent initargs))
   (let ((object (allocate-instance (find-class class-name))))
     (loop for (slot-name value) on initargs by #'cddr do
           (setf (slot-value object slot-name) value))
     (update-instance-after-reading object)))

(defun print-value-object (object stream)
   (let ((*print-circle* nil))
     (format stream "#.(VALUE-OBJECT '~S" (class-name (class-of object)))
     (loop for slot in (class-slots (class-of object))
           unless (eq (slot-definition-allocation slot) :class) do
           (format stream " '~S '~S"
                   (slot-definition-name slot)
                   (slot-value object (slot-definition-name slot))))
     (format stream ")")))

(defmethod print-object ((object value-object) stream)
   (if *print-readably*
     (print-value-object object stream)
     (call-next-method)))

(defclass funcallable-value-object ()
   ((definition :initarg :definition
                :reader funcallable-instance-definition))
   (:metaclass funcallable-standard-class))

(defmethod initialize-instance :after
   ((object funcallable-value-object) &key definition)
   (set-funcallable-instance-function object (compile nil definition)))

(defmethod reinitialize-instance :after
   ((object funcallable-value-object) &key (definition nil definitionp))
   (when definitionp
     (set-funcallable-instance-function
       object (compile nil definition))))

(defmethod update-instance-after-reading :after
   ((object funcallable-value-object))
   (set-funcallable-instance-function
     object (compile nil (funcallable-instance-definition object))))

(defmethod print-object ((object funcallable-value-object) stream)
   (if *print-readably*
     (print-value-object object stream)
     (call-next-method)))

(defmacro vlambda ((&rest lambda-list) &body body)
   `(make-instance 'funcallable-value-object
                   :definition '(lambda ,lambda-list ,@body)))

(defmacro define-vfunction (name (&rest lambda-list) &body body)
   `(progn
      (declaim (notinline ,name))
      (defun ,name ,lambda-list)
      (setf (fdefinition ',name)
            (vlambda ,lambda-list ,@body))
      ',name))


-- 
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: Volkan YAZICI
Subject: Re: serialization of functions/closures
Date: 
Message-ID: <5894abb9-a93e-43aa-99a2-bab144c81a44@o40g2000prn.googlegroups.com>
On Jan 1, 10:20 pm, Pascal Costanza <····@p-cos.net> wrote:
> Closures are hard: When serialized to another location, do you want to
> see the same bindings as the original closure? Do you want to ensure
> that side effects on the bindings are signaled back to the original
> location? Should side effects from the original location always be
> propagated to the new location?
>
> Functions that don't close over anything are easy. Here is a sketch that
> we used in some project:
>
> (in-package :closer-common-lisp-user)
>
> (defgeneric update-instance-after-reading (object)
>    (:method ((object t)) object))
>
> (defclass value-object () ())
>
> (defun value-object (class-name &rest initargs)
>    (declare (dynamic-extent initargs))
>    (let ((object (allocate-instance (find-class class-name))))
>      (loop for (slot-name value) on initargs by #'cddr do
>            (setf (slot-value object slot-name) value))
>      (update-instance-after-reading object)))
>
> (defun print-value-object (object stream)
>    (let ((*print-circle* nil))
>      (format stream "#.(VALUE-OBJECT '~S" (class-name (class-of object)))
>      (loop for slot in (class-slots (class-of object))
>            unless (eq (slot-definition-allocation slot) :class) do
>            (format stream " '~S '~S"
>                    (slot-definition-name slot)
>                    (slot-value object (slot-definition-name slot))))
>      (format stream ")")))
>
> (defmethod print-object ((object value-object) stream)
>    (if *print-readably*
>      (print-value-object object stream)
>      (call-next-method)))
>
> (defclass funcallable-value-object ()
>    ((definition :initarg :definition
>                 :reader funcallable-instance-definition))
>    (:metaclass funcallable-standard-class))
>
> (defmethod initialize-instance :after
>    ((object funcallable-value-object) &key definition)
>    (set-funcallable-instance-function object (compile nil definition)))
>
> (defmethod reinitialize-instance :after
>    ((object funcallable-value-object) &key (definition nil definitionp))
>    (when definitionp
>      (set-funcallable-instance-function
>        object (compile nil definition))))
>
> (defmethod update-instance-after-reading :after
>    ((object funcallable-value-object))
>    (set-funcallable-instance-function
>      object (compile nil (funcallable-instance-definition object))))
>
> (defmethod print-object ((object funcallable-value-object) stream)
>    (if *print-readably*
>      (print-value-object object stream)
>      (call-next-method)))
>
> (defmacro vlambda ((&rest lambda-list) &body body)
>    `(make-instance 'funcallable-value-object
>                    :definition '(lambda ,lambda-list ,@body)))
>
> (defmacro define-vfunction (name (&rest lambda-list) &body body)
>    `(progn
>       (declaim (notinline ,name))
>       (defun ,name ,lambda-list)
>       (setf (fdefinition ',name)
>             (vlambda ,lambda-list ,@body))
>       ',name))

Despite dozens of previous closure serialization related threads, this
is the first time I see such a CLOS hack for wrapping classes around
(almost pseudo) functions for serialization purposes. Neat! Which
resource (article, book, etc.) one should _digest_ to be able to do
similar CLOS hacks?


Regards.
From: Pascal Costanza
Subject: Re: serialization of functions/closures
Date: 
Message-ID: <6s69nbF4eccqU1@mid.individual.net>
Volkan YAZICI wrote:
> On Jan 1, 10:20 pm, Pascal Costanza <····@p-cos.net> wrote:
>> Closures are hard: When serialized to another location, do you want to
>> see the same bindings as the original closure? Do you want to ensure
>> that side effects on the bindings are signaled back to the original
>> location? Should side effects from the original location always be
>> propagated to the new location?
>>
>> Functions that don't close over anything are easy. Here is a sketch that
>> we used in some project:
[...]

> Despite dozens of previous closure serialization related threads, this
> is the first time I see such a CLOS hack for wrapping classes around
> (almost pseudo) functions for serialization purposes. Neat! Which
> resource (article, book, etc.) one should _digest_ to be able to do
> similar CLOS hacks?

There is no single article or book that helps to come up with such a 
solution.

The ingredients are the following:

+ Ignore people who say that CLOS sucks. ;) They just don't understand 
it and don't know what they are talking about. [1]

+ Especially understand that CLOS is not about OOP, but about generic 
functions. That's an important shift of perspective. If you cannot make 
that shift, you don't "get" it. Read Jim Newton's and Christophe Rhode's 
papers about custom specializers for CLOS, or my paper about Filtered 
Dispatch - these papers should help getting that perspective.

+ Read about the CLOS MOP. The important material is: Andreas Paepcke, 
"User-Level Language Crafting"; Gregor Kiczales et al., "The Art of the 
Metaobject Protocol"; http://www.lisp.org/mop/

+ Read about macros. I learned macros from Paul Graham's "On Lisp", but 
Peter Norvig's "Paradigms of Artificial Intelligence Programming" is 
also good reading.

+ Read about metacircular interpreters. I can especially recommend 
Steele's and Sussman's "The Art of the Interpreter" (see the Lambda 
Papers at http://library.readscheme.org ). Paul Graham's "The Roots of 
Lisp" may also be helpful as a starting point. Other people recommend 
SICP and PAIP, but I  don't find them that illuminating in this regard.

+ Finally the hard point: Try to understand reflection and especially 
3-Lisp. There is a section about reflection at 
http://library.readscheme.org but the original material about 3-Lisp is 
harder to find. I can recommend Charlotte Herzeel's paper "Reflection 
for the Masses" as introductory reading. (If you can find the "Interim 
3-Lisp Manual", that's also highly recommended.)

What's important in the context of the code posted here is that there is 
a notion of "shifting up" and "shifting down" in 3-Lisp when you switch 
between meta-level and base-level code. (compile nil '(lambda ...)) is a 
way in Common Lisp to "shift down" from a description of some code to an 
actual function that runs this code. In Common Lisp, however, there is 
no corresponding operation to "shift up" from a function back to its 
description - what the value functions do in this code is basically 
provide a way to "shift up" by recording the function definition that 
produced the function and keeping it available.

CLOS already needs such a way to "shift up" and "shift down" - whenever 
you add a method to a generic function, a new ("discriminating") 
function is computed (by way of a "downshift"), but the list of methods 
associated with a generic function needs to be maintained for 
introspection. So the solution here is to basically just reuse this 
machinery, which is exposed in the CLOS MOP by way of funcallable objects.

+ Another important point is to make the serialization itself work. I 
can highly recommend Arthur Lemmens's "Persistence in Common Lisp" in 
this regard, which discusses how to use #. for serialization, including 
its disadvantages (which can be serious, depending on the actual 
requirements!).


I hope this helps.


Pascal


[1] This applies even to people who have been using CLOS for years, and 
then came to the "conclusion" that CLOS sucks. (That's the disadvantage 
of trying hard to remain a mere application programmer, you don't think 
hard enough about what you're doing.)

-- 
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: Rob Warnock
Subject: Re: serialization of functions/closures
Date: 
Message-ID: <MbadnYxgQJPDa8DUnZ2dnUVZ_rmdnZ2d@speakeasy.net>
Pascal Costanza  <··@p-cos.net> wrote:
+---------------
| Volkan YAZICI wrote:
| > Which resource (article, book, etc.) one should _digest_ to
| > be able to do similar CLOS hacks?
...
| + Read about metacircular interpreters. I can especially recommend 
| Steele's and Sussman's "The Art of the Interpreter" (see the Lambda 
| Papers at http://library.readscheme.org ). Paul Graham's "The Roots of 
| Lisp" may also be helpful as a starting point. Other people recommend 
| SICP and PAIP, but I  don't find them that illuminating in this regard.
+---------------

Better, at least for the serious student, is Christian Queinnec's
"Lisp in Small Pieces" (LiSP) [Les Langages Lisp, in the original
French]. What's really good about this one is that for each language
feature that it covers, it gives you several approaches to implementing
it and discusses the tradeoffs. I perticularly liked Chapter 6, "Fast
Interpretation", which discusses preprocessing [in CL terms, think
"minimal compilation"] to speed interpretation.


-Rob

-----
Rob Warnock			<····@rpw3.org>
627 26th Avenue			<URL:http://rpw3.org/>
San Mateo, CA 94403		(650)572-2607
From: Matthew D Swank
Subject: Re: serialization of functions/closures
Date: 
Message-ID: <27G7l.113004$sC4.11605@newsfe04.iad>
On Fri, 02 Jan 2009 11:48:10 +0100, Pascal Costanza wrote:

> + Ignore people who say that CLOS sucks.  They just don't understand it
> and don't know what they are talking about. [1]

...

> 
> [1] This applies even to people who have been using CLOS for years, and
> then came to the "conclusion" that CLOS sucks. (That's the disadvantage
> of trying hard to remain a mere application programmer, you don't think
> hard enough about what you're doing.)

Kenny ends up in threads in which he's not even participating.

-- 
Expect the worst, it's the least you can do.
From: Alex Mizrahi
Subject: Re: serialization of functions/closures
Date: 
Message-ID: <495e325d$0$90276$14726298@news.sunsite.dk>
 VY> is the first time I see such a CLOS hack

i'd say it is nearly trivial use of funcallable instances.

 VY> Which resource (article, book, etc.) one should
 VY> _digest_ to be able to do similar CLOS hacks?

i guess MOP documentation should do.