From: Ron Garret
Subject: A cool thing Lisp can do...
Date: 
Message-ID: <rNOSPAMon-662EB9.19001227042005@news.gha.chartermi.net>
... that no other language can (as far as I know):

Suppose you have a class for which generating instances is expensive:

(defun expensive-function () (print 'Crunching...))
(defclass expensive-class () ((x :initform (expensive-function))))

and it has a whole pile of methods defined on it:

(defmethod m1 ((x expensive-class)) (print 'm1))
(defmethod m2 ((x expensive-class)) (print 'm2))
(defmethod m3 ((x expensive-class)) (print 'm3))

and you have some code that looks like this:

(let ( (l (make-a-very-long-list-of-expensive-class-instances)) )
  (some-function-that-only-uses-a-few-of-those-instances l))

This is horribly inefficient because you are making instances of 
expensive-class that might not be used.  Fixing this would normally be a 
major project.  But in Lisp you can write a generic proxy that is a lazy 
stand-in for an instance of not only expensive-class, but ANY CLASS AT 
ALL!  Furthermore, you can do this in less than ten lines of code:

(defclass proxy () ((type :initarg :type) (initargs :initarg :initargs)))

(defmethod reify ((p proxy))
  (with-slots (type initargs) p
    (let ( (initargs initargs) ) ; Because it's about to go away
      (change-class p type)        ; Poof!
      (apply 'initialize-instance p initargs))))

(defmethod no-applicable-method ((f standard-generic-function)
                                 &rest args)
  (if (typep (car args) 'proxy)
    (apply f (reify (car args)) (cdr args))
    (call-next-method)))

You can now make proxy objects that are completely plug-compatible 
stand-ins for instances of expensive-class, but for which you don't have 
to pay until you actually use them:

? (setf p (make-instance 'proxy :type 'expensive-class :initargs nil))
#<PROXY #x25B7CCE>
? (m1 p)

CRUNCHING... 
M1 
M1
? (m2 p)

M2 
M2
? (m3 p)

M3 
M3
? 

So all you have to do now is create a list of expensive-class proxies 
and watch your code speed up!

This turns out to be tremendously handy if, for example, initializing 
expensive-class involves touching a file or a database.

As far as I know this is not possible in any other language, let alone 
in fewer than ten lines of code.

rg

From: Andy Cristina
Subject: Re: A cool thing Lisp can do...
Date: 
Message-ID: <8D_be.74$Rk4.37@okepread05>
While this completely blows me away, I wanted to get something 
clarified... your initargs won't be evaulated at proxy creation time, 
will they?  It looks to me like they will be evaluated at reification 
time, but I'm not sure.  I am still very much new.

Ron Garret wrote:
> ... that no other language can (as far as I know):
> 
> Suppose you have a class for which generating instances is expensive:
> 
> (defun expensive-function () (print 'Crunching...))
> (defclass expensive-class () ((x :initform (expensive-function))))
> 
> and it has a whole pile of methods defined on it:
> 
> (defmethod m1 ((x expensive-class)) (print 'm1))
> (defmethod m2 ((x expensive-class)) (print 'm2))
> (defmethod m3 ((x expensive-class)) (print 'm3))
> 
> and you have some code that looks like this:
> 
> (let ( (l (make-a-very-long-list-of-expensive-class-instances)) )
>   (some-function-that-only-uses-a-few-of-those-instances l))
> 
> This is horribly inefficient because you are making instances of 
> expensive-class that might not be used.  Fixing this would normally be a 
> major project.  But in Lisp you can write a generic proxy that is a lazy 
> stand-in for an instance of not only expensive-class, but ANY CLASS AT 
> ALL!  Furthermore, you can do this in less than ten lines of code:
> 
> (defclass proxy () ((type :initarg :type) (initargs :initarg :initargs)))
> 
> (defmethod reify ((p proxy))
>   (with-slots (type initargs) p
>     (let ( (initargs initargs) ) ; Because it's about to go away
>       (change-class p type)        ; Poof!
>       (apply 'initialize-instance p initargs))))
> 
> (defmethod no-applicable-method ((f standard-generic-function)
>                                  &rest args)
>   (if (typep (car args) 'proxy)
>     (apply f (reify (car args)) (cdr args))
>     (call-next-method)))
> 
> You can now make proxy objects that are completely plug-compatible 
> stand-ins for instances of expensive-class, but for which you don't have 
> to pay until you actually use them:
> 
> ? (setf p (make-instance 'proxy :type 'expensive-class :initargs nil))
> #<PROXY #x25B7CCE>
> ? (m1 p)
> 
> CRUNCHING... 
> M1 
> M1
> ? (m2 p)
> 
> M2 
> M2
> ? (m3 p)
> 
> M3 
> M3
> ? 
> 
> So all you have to do now is create a list of expensive-class proxies 
> and watch your code speed up!
> 
> This turns out to be tremendously handy if, for example, initializing 
> expensive-class involves touching a file or a database.
> 
> As far as I know this is not possible in any other language, let alone 
> in fewer than ten lines of code.
> 
> rg
From: Pascal Bourguignon
Subject: Re: A cool thing Lisp can do...
Date: 
Message-ID: <87acnjl89k.fsf@thalassa.informatimago.com>
Andy Cristina <·············@gmail.com> writes:

> While this completely blows me away, I wanted to get something
> clarified... your initargs won't be evaulated at proxy creation time,
> will they?  It looks to me like they will be evaluated at reification
> time, but I'm not sure.  I am still very much new.

See my signature!

If you had edited the quote and inserted your comment near the
relevant part, perhaps you'd have noted yourself that:

> Ron Garret wrote:
>>[...]
>> ? (setf p (make-instance 'proxy :type 'expensive-class :initargs nil))

make-instance is a function that evaluate its arguments including the initargs!

What _will_ be evaluated at reification time is the initform, as we want.

-- 
A: Because it messes up the order in which people normally read text.
Q: Why is top-posting such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
__Pascal Bourguignon__                     http://www.informatimago.com/
From: Thomas F. Burdick
Subject: Re: A cool thing Lisp can do...
Date: 
Message-ID: <xcv7jin9w2n.fsf@conquest.OCF.Berkeley.EDU>
Ron Garret <·········@flownet.com> writes:

> ... that no other language can (as far as I know):
[...]
> As far as I know this is not possible in any other language, let alone 
> in fewer than ten lines of code.

Smalltalk can do this, too.  Proxy objects are a common thing in that
language community.  I don't have a ST here, and my ST skills are too
rusty to do it cold, but the basic approach would be the same, using
the changeClass and doesNotUnderstand methods.

However, your Lisp approach is a little *too* Smalltalky for my taste:

> (defmethod no-applicable-method ((f standard-generic-function)
>                                  &rest args)
>   (if (typep (car args) 'proxy)
>     (apply f (reify (car args)) (cdr args))
>     (call-next-method)))

I'd expect this to work for proxies in any position.  Something like:

  (defmethod no-applicable-method ((f standard-generic-function) &rest args)
    (let* ((found-one nil)
  	   (args (mapcar (lambda (arg)
  			   (if (typep arg 'proxy)
  			       (prog1 (reify arg)
  				 (setf found-one t))
  			       arg))
                         args)))
      (if found-one (apply f args) (call-next-method))))

I agree, this is really cool.  With full multi-method support for
proxies, I'm back to the start of your post: I don't think any other
language can do that.
From: Pascal Bourguignon
Subject: Re: A cool thing Lisp can do...
Date: 
Message-ID: <8764y7kzbf.fsf@thalassa.informatimago.com>
···@conquest.OCF.Berkeley.EDU (Thomas F. Burdick) writes:

> Ron Garret <·········@flownet.com> writes:
>
>> ... that no other language can (as far as I know):
> [...]
>> As far as I know this is not possible in any other language, let alone 
>> in fewer than ten lines of code.
>
> Smalltalk can do this, too.  Proxy objects are a common thing in that
> language community.  I don't have a ST here, and my ST skills are too
> rusty to do it cold, but the basic approach would be the same, using
> the changeClass and doesNotUnderstand methods.

Well, if you walk this way, in Objective-C too  proxies are easily
implemented, since it's kind of smalltalkish.  Distributed Object and
Portable Distributed Object use them a lot.


> However, your Lisp approach is a little *too* Smalltalky for my taste:
>
>> (defmethod no-applicable-method ((f standard-generic-function)
>>                                  &rest args)
>>   (if (typep (car args) 'proxy)
>>     (apply f (reify (car args)) (cdr args))
>>     (call-next-method)))
>
> I'd expect this to work for proxies in any position.  Something like:
>
>   (defmethod no-applicable-method ((f standard-generic-function) &rest args)
>     (let* ((found-one nil)
>   	   (args (mapcar (lambda (arg)
>   			   (if (typep arg 'proxy)
>   			       (prog1 (reify arg)
>   				 (setf found-one t))
>   			       arg))
>                          args)))
>       (if found-one (apply f args) (call-next-method))))
>
> I agree, this is really cool.  With full multi-method support for
> proxies, I'm back to the start of your post: I don't think any other
> language can do that.

-- 
__Pascal Bourguignon__                     http://www.informatimago.com/
In deep sleep hear sound,
Cat vomit hairball somewhere.
Will find in morning.
From: Thomas F. Burdick
Subject: Re: A cool thing Lisp can do...
Date: 
Message-ID: <xcv1x8uadiq.fsf@conquest.OCF.Berkeley.EDU>
Pascal Bourguignon <···@informatimago.com> writes:

> ···@conquest.OCF.Berkeley.EDU (Thomas F. Burdick) writes:
> 
> > Ron Garret <·········@flownet.com> writes:
> >
> >> ... that no other language can (as far as I know):
> > [...]
> >> As far as I know this is not possible in any other language, let alone 
> >> in fewer than ten lines of code.
> >
> > Smalltalk can do this, too.  Proxy objects are a common thing in that
> > language community.  I don't have a ST here, and my ST skills are too
> > rusty to do it cold, but the basic approach would be the same, using
> > the changeClass and doesNotUnderstand methods.
> 
> Well, if you walk this way, in Objective-C too  proxies are easily
> implemented, since it's kind of smalltalkish.

"ish".  ObjC doesn't have a change-class equivalent, nor can it
because its "objects" are C structs.
From: Edi Weitz
Subject: Re: A cool thing Lisp can do...
Date: 
Message-ID: <ull73oyrv.fsf@agharta.de>
On 28 Apr 2005 00:53:04 -0700, ···@conquest.OCF.Berkeley.EDU (Thomas F. Burdick) wrote:

[...]

Where's the cat, BTW?

Cheers,
Edi.

-- 

Lisp is not dead, it just smells funny.

Real email: (replace (subseq ·········@agharta.de" 5) "edi")
From: Thomas F. Burdick
Subject: Re: A cool thing Lisp can do...
Date: 
Message-ID: <xcvy8b28ys0.fsf@conquest.OCF.Berkeley.EDU>
Edi Weitz <········@agharta.de> writes:

> On 28 Apr 2005 00:53:04 -0700, ···@conquest.OCF.Berkeley.EDU (Thomas F. Burdick) wrote:
> 
> [...]
> 
> Where's the cat, BTW?

I've since become a militarist :-)

But seriously ... as time passed, she was sounding absurdly
agitational (as opposed to propagandistic, which was the intent).
She'll be back at some point, when I have a chance to get her to sound
a little less like she's making an active call-to-arms.
From: Willem Broekema
Subject: Re: A cool thing Lisp can do...
Date: 
Message-ID: <1114695056.985217.108160@o13g2000cwo.googlegroups.com>
Ron Garret wrote:
> (defmethod no-applicable-method ((f standard-generic-function)
>                                  &rest args)
>  [...])

This is not allowed, as:

"Portable programs must not redefine any specified classes, generic
functions, methods or method combinations. Any method defined by a
portable program on a specified generic function must have at least one
specializer that is neither a specified class nor an eql specializer
whose associated value is an instance of a specified class."

 - http://www.lisp.org/mop/concepts.html#portable

Using this rule, implementations can get efficiency by inlining the
no-applicable-method logic when the first argument is a normal generic
function (which is the common case).

You could subclass standard-generic-function and specialize
no-applicable-method on that class, but that would obviously not
intercept the generic function calls from your example.

- Willem
From: Ron Garret
Subject: Re: A cool thing Lisp can do...
Date: 
Message-ID: <rNOSPAMon-651656.08532828042005@news.gha.chartermi.net>
In article <························@o13g2000cwo.googlegroups.com>,
 "Willem Broekema" <······@pastelhorn.com> wrote:

> Ron Garret wrote:
> > (defmethod no-applicable-method ((f standard-generic-function)
> >                                  &rest args)
> >  [...])
> 
> This is not allowed,

Well, that's not quite true.  It's not allowed in portable code, but 
nothing prevents an implementation from supporting it.  And obviously at 
least one implementation (MCL, and hence presumably openMCL as well) 
does.

> You could subclass standard-generic-function and specialize
> no-applicable-method on that class, but that would obviously not
> intercept the generic function calls from your example.

If you really need guaranteed portability you could put the 
expensive-class code in a used-defined package and shadow defmethod to 
define methods on a new generic function class.  Of course, now you're 
up to twenty lines of code or so.

rg
From: Pascal Costanza
Subject: Re: A cool thing Lisp can do...
Date: 
Message-ID: <3dcfqoF6sb2l7U1@individual.net>
Ron Garret wrote:
> In article <························@o13g2000cwo.googlegroups.com>,
>  "Willem Broekema" <······@pastelhorn.com> wrote:
> 
> 
>>Ron Garret wrote:
>>
>>>(defmethod no-applicable-method ((f standard-generic-function)
>>>                                 &rest args)
>>> [...])
>>
>>This is not allowed,
> 
> 
> Well, that's not quite true.  It's not allowed in portable code, but 
> nothing prevents an implementation from supporting it.  And obviously at 
> least one implementation (MCL, and hence presumably openMCL as well) 
> does.

Be careful not to draw conclusions from working examples - they may just 
work accidentally. The restriction Willem talks about allows CLOS to 
inline code when it can prove that nothing stands in the way of doing 
so. This especially means that it may inline some cases but not in 
others, so you may have just stumbled upon a case where no code 
optimization takes place.

Surely, a specific implementation may support what you want, but only if 
this is documented you can be really sure about it. The MCL 
documentations don't say anything about that specific case.

This is not theoretical paranoia, but happened to me a few times.

>>You could subclass standard-generic-function and specialize
>>no-applicable-method on that class, but that would obviously not
>>intercept the generic function calls from your example.
> 
> If you really need guaranteed portability you could put the 
> expensive-class code in a used-defined package and shadow defmethod to 
> define methods on a new generic function class.  Of course, now you're 
> up to twenty lines of code or so.

Right.


Pascal

-- 
2nd European Lisp and Scheme Workshop
July 26 - Glasgow, Scotland - co-located with ECOOP 2005
http://lisp-ecoop05.bknr.net/
From: Thomas A. Russ
Subject: Re: A cool thing Lisp can do...
Date: 
Message-ID: <ymill72x0rb.fsf@sevak.isi.edu>
Pascal Costanza <··@p-cos.net> writes:

> 
> Ron Garret wrote:
> > In article <························@o13g2000cwo.googlegroups.com>,
> >  "Willem Broekema" <······@pastelhorn.com> wrote:
> > 
> > 
> >>Ron Garret wrote:
> >>
> >>>(defmethod no-applicable-method ((f standard-generic-function)
> >>>                                 &rest args)
> >>> [...])
> >>
> >>This is not allowed,
> > 
> > 
> > Well, that's not quite true.  It's not allowed in portable code, but 
> > nothing prevents an implementation from supporting it.  And obviously at 
> > least one implementation (MCL, and hence presumably openMCL as well) 
> > does.
> 
> Be careful not to draw conclusions from working examples - they may just 
> work accidentally. The restriction Willem talks about allows CLOS to 
> inline code when it can prove that nothing stands in the way of doing 
> so. This especially means that it may inline some cases but not in 
> others, so you may have just stumbled upon a case where no code 
> optimization takes place.

Hmmm.  Now I always thought that the reason for the portable code
restriction was to prevent bad interactions between code bases.  For
example, if Ron's package defined his NO-APPLICABLE-METHOD method on
STANDARD-GENERIC-FUNCTION and I defined my different method the same
way, then we would not be able to load both packages into the same lisp
and have them work.

I suppose there is an optimization issue as well, but for me the main
point was always about making sure the code wouldn't do anything that
made it potentially interfere with other code.

-- 
Thomas A. Russ,  USC/Information Sciences Institute
From: Pascal Costanza
Subject: Re: A cool thing Lisp can do...
Date: 
Message-ID: <3dcmddF6prs39U1@individual.net>
Thomas A. Russ wrote:
> Pascal Costanza <··@p-cos.net> writes:
> 
>>Ron Garret wrote:
>>
>>>In article <························@o13g2000cwo.googlegroups.com>,
>>> "Willem Broekema" <······@pastelhorn.com> wrote:
>>>
>>>>Ron Garret wrote:
>>>>
>>>>
>>>>>(defmethod no-applicable-method ((f standard-generic-function)
>>>>>                                &rest args)
>>>>>[...])
>>>>
>>>>This is not allowed,
>>>
>>>
>>>Well, that's not quite true.  It's not allowed in portable code, but 
>>>nothing prevents an implementation from supporting it.  And obviously at 
>>>least one implementation (MCL, and hence presumably openMCL as well) 
>>>does.
>>
>>Be careful not to draw conclusions from working examples - they may just 
>>work accidentally. The restriction Willem talks about allows CLOS to 
>>inline code when it can prove that nothing stands in the way of doing 
>>so. This especially means that it may inline some cases but not in 
>>others, so you may have just stumbled upon a case where no code 
>>optimization takes place.
> 
> Hmmm.  Now I always thought that the reason for the portable code
> restriction was to prevent bad interactions between code bases.  For
> example, if Ron's package defined his NO-APPLICABLE-METHOD method on
> STANDARD-GENERIC-FUNCTION and I defined my different method the same
> way, then we would not be able to load both packages into the same lisp
> and have them work.
> 
> I suppose there is an optimization issue as well, but for me the main
> point was always about making sure the code wouldn't do anything that
> made it potentially interfere with other code.

Er, yes, that's another reason, and for some restrictions indeed the 
only one. But in other cases, optimization of the standard cases was 
considered important. At least that's what I recall reading.


Pascal

-- 
2nd European Lisp and Scheme Workshop
July 26 - Glasgow, Scotland - co-located with ECOOP 2005
http://lisp-ecoop05.bknr.net/
From: Alexander Schmolck
Subject: Re: A cool thing Lisp can do...
Date: 
Message-ID: <yfsk6mn9rh1.fsf@black4.ex.ac.uk>
Ron Garret <·········@flownet.com> writes:

> As far as I know this is not possible in any other language, let alone 
> in fewer than ten lines of code.

Doesn't this do what you want?

    class proxy(object):
        def __init__(self, typeToProxy, *args, **kwargs):
            self.__typeToProxy,self.__args,self.__kwargs = typeToProxy, args, kwargs
        def __getattr__(self, name):
            self.__class__ = self.__typeToProxy
            self.__init__(*self.__args, **self.__kwargs)
            return getattr(self, name)

    class ExpensiveClass(object):
        def __init__(self, x):
            self.x = x
        def m1(self): print 'called m1 with x:', self.x

    p = proxy(ExpensiveClass, x='the new z')
    print 'before', type(p)
    p.m1()
    print 'after', type(p)

'as
From: Ron Garret
Subject: Re: A cool thing Lisp can do...
Date: 
Message-ID: <rNOSPAMon-86A45B.08411228042005@news.gha.chartermi.net>
In article <···············@black4.ex.ac.uk>,
 Alexander Schmolck <··········@gmx.net> wrote:

> Ron Garret <·········@flownet.com> writes:
> 
> > As far as I know this is not possible in any other language, let alone 
> > in fewer than ten lines of code.
> 
> Doesn't this do what you want?
> 
>     class proxy(object):
>         def __init__(self, typeToProxy, *args, **kwargs):
>             self.__typeToProxy,self.__args,self.__kwargs = typeToProxy, args, 
>             kwargs
>         def __getattr__(self, name):
>             self.__class__ = self.__typeToProxy
>             self.__init__(*self.__args, **self.__kwargs)
>             return getattr(self, name)
> 
>     class ExpensiveClass(object):
>         def __init__(self, x):
>             self.x = x
>         def m1(self): print 'called m1 with x:', self.x
> 
>     p = proxy(ExpensiveClass, x='the new z')
>     print 'before', type(p)
>     p.m1()
>     print 'after', type(p)


Yeah, but Python is just Lisp with a funny syntax ;-)

Seriously, I didn't know that you could muck with self.__class__.  
(Actually, I still don't know this.  It seems to work empirically, but 
can you really rely on it?)

rg
From: ·················@gmail.com
Subject: Re: A cool thing Lisp can do...
Date: 
Message-ID: <1114705922.974287.134030@f14g2000cwb.googlegroups.com>
Ron Garret:

> Seriously, I didn't know that you could muck with self.__class__.
> (Actually, I still don't know this.  It seems to work empirically,
but
> can you really rely on it?)

AFAIK, there are the following rules:

1. you cannot change the class of a built-in object (an integer, a
string, etc.)
2. you cannot change the class of a user-defined object to be a
built-in class;
3. you can change the class of a user-defined object to be a
user-defined class;
4. since classes are regular objects, the same rules hold for
metaclasses.

In earlier version of Python (2.2.something) the restriction 2 was
absent;
it was added after the introduction of the boolean type to make sure
that instances of 'bool' are 0 and 1 and nothing else. So now if
type(X) == built-in type, you are sure that X is really a built-in
object,
not something else which class has been changed.

Of course, when you change the class, it is best if you change it with
a
subclass of the original class. A part for proxy tricks, I know only of
another example where changing the class of an object may be useful:

def addmethod(meth, instance): # from a recipe by Alex Martelli
    """Add a method to a specific instance. Works by changing the class
    of the instance to a newly generated subclass of the original
class.

    >>> class C(object): pass
    >>> c1 = C(); c2 = C()
    >>> def __str__(self): return "works!"
    >>> addmethod(__str__, c1)
    >>> print c1
    works!
    >>> print c2 #doctest: +ELLIPSIS
    <...C object at ...>
    """
    instance.__class__ = type("Sub" + instance.__class__.__name__,
                              (instance.__class__, ), {meth.__name__ :
meth})
From: Ron Garret
Subject: Re: A cool thing Lisp can do...
Date: 
Message-ID: <rNOSPAMon-0649CC.15492628042005@news.gha.chartermi.net>
In article <························@f14g2000cwb.googlegroups.com>,
 ·················@gmail.com wrote:

> Ron Garret:
> 
> > Seriously, I didn't know that you could muck with self.__class__.
> > (Actually, I still don't know this.  It seems to work empirically,
> but
> > can you really rely on it?)
> 
> AFAIK, there are the following rules:
> 
> 1. you cannot change the class of a built-in object (an integer, a
> string, etc.)
> 2. you cannot change the class of a user-defined object to be a
> built-in class;
> 3. you can change the class of a user-defined object to be a
> user-defined class;
> 4. since classes are regular objects, the same rules hold for
> metaclasses.

Apparently this is not a complete list because the following doesn't 
work:

Python 2.4 (#2, Apr 12 2005, 09:22:44) 
[GCC 3.3 20030304 (Apple Computer, Inc. build 1640)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> class C1(dict): pass
... 
>>> class C2(object): pass
... 
>>> C2().__class__=C1
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
TypeError: __class__ assignment: 'C2' object layout differs from 'C1'
>>> C1().__class__=C2
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
TypeError: __class__ assignment: 'C1' object layout differs from 'C2'


This is despite the fact that dict is a subclass of object.

rg
From: ·················@gmail.com
Subject: Re: A cool thing Lisp can do...
Date: 
Message-ID: <1114746528.354981.35340@f14g2000cwb.googlegroups.com>
You are right, I forgot this. But the error message about "object
layout" reminded
me that you may have problems with __slots__, and actually this is the
case:

>>> class C(object):
...     __slots__=["some_slot"]
...
>>> class D(object):
...     pass
...
>>> D().__class__ = C
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
TypeError: __class__ assignment: 'D' object layout differs from 'C'
>>> C().__class__ = D
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
TypeError: __class__ assignment: 'C' object layout differs from 'D'

I never use slots, anyway ;)

Also, remember that built-in classes are still a bit special, so you
cannot
multiply inherit from two built-in classes at the same time.

               Michele Simionato
From: Karl A. Krueger
Subject: Re: A cool thing Lisp can do...
Date: 
Message-ID: <d4s3h0$hkq$2@baldur.whoi.edu>
Ron Garret <·········@flownet.com> wrote:
> In article <························@f14g2000cwb.googlegroups.com>,
> ·················@gmail.com wrote:
>> AFAIK, there are the following rules:
>> 
>> 1. you cannot change the class of a built-in object (an integer, a
>> string, etc.)
>> 2. you cannot change the class of a user-defined object to be a
>> built-in class;
>> 3. you can change the class of a user-defined object to be a
>> user-defined class;
>> 4. since classes are regular objects, the same rules hold for
>> metaclasses.
> 
> Apparently this is not a complete list because the following doesn't 
> work:

You cannot change the class of an object whose class is a subclass of a
built-in class (e.g. dict).  You cannot change class _to_ a class which
is a subclass of a built-in class (e.g. dict).

"object" does not count as a built-in class for this rule.  :)

-- 
Karl A. Krueger <········@example.edu> { s/example/whoi/ }
From: Ron Garret
Subject: Re: A cool thing Lisp can do...
Date: 
Message-ID: <rNOSPAMon-EAFD6C.19332529042005@news.gha.chartermi.net>
In article <············@baldur.whoi.edu>,
 "Karl A. Krueger" <········@example.edu> wrote:

> Ron Garret <·········@flownet.com> wrote:
> > In article <························@f14g2000cwb.googlegroups.com>,
> > ·················@gmail.com wrote:
> >> AFAIK, there are the following rules:
> >> 
> >> 1. you cannot change the class of a built-in object (an integer, a
> >> string, etc.)
> >> 2. you cannot change the class of a user-defined object to be a
> >> built-in class;
> >> 3. you can change the class of a user-defined object to be a
> >> user-defined class;
> >> 4. since classes are regular objects, the same rules hold for
> >> metaclasses.
> > 
> > Apparently this is not a complete list because the following doesn't 
> > work:
> 
> You cannot change the class of an object whose class is a subclass of a
> built-in class (e.g. dict).  You cannot change class _to_ a class which
> is a subclass of a built-in class (e.g. dict).
> 
> "object" does not count as a built-in class for this rule.  :)

Turns out there's another restriction: you cannot change from or to a 
class that has __slots__ set.

I think it's fair to say that Python can't do generic proxies.

rg
From: ·················@gmail.com
Subject: Re: A cool thing Lisp can do...
Date: 
Message-ID: <1114833043.886860.163350@f14g2000cwb.googlegroups.com>
Ron Garrett:
> I think it's fair to say that Python can't do generic proxies.

Well, actually this only means that you should not use __slots__ ;)

           Michele Simionato
From: Marco Antoniotti
Subject: Re: A cool thing Lisp can do...
Date: 
Message-ID: <ynsde.18$mi7.55076@typhoon.nyu.edu>
·················@gmail.com wrote:
> Ron Garrett:
> 
>>I think it's fair to say that Python can't do generic proxies.
> 
> 
> Well, actually this only means that you should not use __slots__ ;)
> 

Actually it means that you shouldn't use Python at all and switch to 
Common Lisp :)

Cheers
--
Marco
From: Marcin 'Qrczak' Kowalczyk
Subject: Re: A cool thing Lisp can do...
Date: 
Message-ID: <87wtqivau7.fsf@qrnik.zagroda>
"Karl A. Krueger" <········@example.edu> writes:

>> Apparently this is not a complete list because the following doesn't 
>> work:
>
> You cannot change the class of an object whose class is a subclass of a
> built-in class (e.g. dict).  You cannot change class _to_ a class which
> is a subclass of a built-in class (e.g. dict).

It's something else. Every Python class have a single ultimate base
built-in type, and you cannot change it dynamically. This type
determines the beginning of the layout of instances.

For example you can't change between something inheriting from string
to something inheriting from list, but you can change between any two
classes inheriting from string.

'object' does count as a built-in type, and an absence of a built-in
base type yields an "old-style class" which is yet different (you
can't change between old-style and new-style dynamically).

-- 
   __("<         Marcin Kowalczyk
   \__/       ······@knm.org.pl
    ^^     http://qrnik.knm.org.pl/~qrczak/