On Thu, 19 Feb 2004, Dan Sugalski wrote:

> I tried to unify attributes and properties--I really did. The
> problem is that they're horribly semantically different. Attributes
> are class private and guaranteed across all objects of a class,
> while properties are ad hoc and can be thrown on anything. Python
> attributes, since they're really done per-object, correspond to our
> properties. I don't want to force things to be one or the other,
> because then you'd be in the unpleasant position of not being able
> to add pythonic attributes to a non-python object.

Hey Dan,

Thanks for taking the time to respond. What you're doing makes a
lot more sense now. Not being able to do both would definitely
suck. So keeping them separate solves that problem. However, I
think there's an alternate solution that would work for both of
us.

First of all, in recent versions of python you CAN create classes
that have fixed slots:

    class Fixed(object):
        __slots__=["foo"]

An instance of this class will demonstrate the problem you're worried about:

    >>> f = Fixed()
    >>> f.foo = 5 # no problem
    >>> f.bar = 6 # big trouble
    Traceback (most recent call last):
      File "<stdin>", line 1, in ?
    AttributeError: 'Fixed' object has no attribute 'bar'


But that's EXACTLY what SHOULD happen if I try to set .bar on
one of these objects, or on any java/perl6/ruby/whatever instance
that doesn't have a .bar slot.


However, in rare cases I might just need to do stick something
extra on that object. If you don't mind a LITTLE kool-ade, you
can use the Decorator design pattern to solve this without
having to change the class at all:


    class PropDecorator(object):
        """
        This class lets you add properties to something
        that wouldn't normally allow it.
        """
        def __init__(self, other):
            super(PropDecorator, self).__setattr__("other", other)

        def __getattr__(self, name):
            try:
                return super(PropDecorator, self).__getattr__(name)
            except AttributeError:
                return getattr(self.other, name)

        def __setattr__(self, name, value):
            try:
                setattr(self.other, name, value)
            except AttributeError:
                super(PropDecorator, self).__setattr__(name, value)


Now you have it both ways:

    >>> p = PropDecorator(f)
    >>> assert p.foo == 5
    >>> p.foo = 2
    >>> assert p.foo == 2
    >>> assert f.foo == 2
    >>> p.bar = 6
    >>> assert p.bar == 6


The nice thing about this is that you only have to incur the
overhead of checking both attributes and properties when you're
actually dealing with both. The compiler doesn't have to emit
anything to check... It just emits getprop, and the PMC does
the right thing.



> Unfortunately the semantics of the two systems don't have any
> overlap, at least no overlap that I can tease out.

To me, the semantics are exactly the same. I have a thing,
and I want to record some information about it. Now some
types of things might have their own ideas about what I
can know about them, and that's cool. Just because I have
a box doesn't mean I get to open it.


> I suppose python code could see all properties and all attributes as
> fully-qualified names, with anything new going into the property
> list, but that's kinda nasty too. Plus there's the issue of python
> code easily seeing attributes that, arguably, it ought not see since
> they're supposed to be mostly class-private.

This is definitely something to think about. The python attitude
is like perl 5's... You can do whatever you want with an object.
But just because you CAN, doesn't mean you SHOULD.

To me, privacy rules are like "the law of the land". An American
object can't legally smoke marijuana... But if you send it over
to Amsterdam, then it's okay. :)

I think it should be the compiler's job to enforce the correct
access privileges. But in any case, this problem exists
regardless of whether you call the opcode setprop or setattr...


> I'm tempted to punt this one to Guido for his opinion.


>
> >For callmeth, callmethcc, and tailcallmeth... I can
> >understand the versions with the string... It looks
> >up the method off of the PMC in P2, right? But what
> >good is the version without the string?
>
> One of the string registers is the name of the sub or method being
> called. The no-string version is supposed to use that. I need to
> document that better. I also need to add in the redispatch ops, which
> I forgot.

Right. I understood that's what you meant. I'm just saying
that that's equivalent to invoke. So what good is it? :)

It's nice to have something that finds the right method,
but since the same work has to be done (move the object
into P2, find the method, invoke it)... Why not leave
the syntactic sugar up to imcc?



> >Again, I'm wary of the separate interface for object
> >stuff.
>
> Well... on the one hand I agree, on the other, method and sub
> dispatch really are very different things. (That might just be the
> dislike of the OO Kool-ade speaking, though :)

:)

How are they different? The calling conventions seem to cover
both of them easily. The only difference I can see is that in
one case, P2 is set to an object.



> >For these two:
> >
> >"""
> >addattr Px, Sy, Sz
> >
> >Add attribute Sy, with a fully-qualified name Sz, to class Px. This
> >will add the attribute slot to all objects of class Px and children of
> >class Px, with a default value of Null
> >
> >removeattr Px, Sy, Sz
> >
> >Remove the attribute Sy (fully qualified name Sz) from class Px,
> >all objects of class Px, and all objects of a child of class Px.
> >"""
> >
> >Shouldn't there be correspdonding vtable methods for these? And shouldn't
> >those methods get to decide how/if the instances are affected?
>
> Well... yeah, there should be. I think. Currently I'm planning on
> peeking inside the guts for parrotclass-based objects and calling a
> method on the class PMC for non-parrotclass objects. I'm assuming,
> perhaps incorrectly, that attribute messing about will be rare enough
> that it doesn't warrant vtable slots. *Does* warrant documentation,
> which I was punting on.


Is there a tradeoff for putting it into the vtable?
If it's a vtable method, then people can implement
their object internals any way they like. Then any
language that doesn't fit exactly with the predefined
ParrotClass/ParrotObject can use it's own schema.

Like personally, I'm still  planning to wrap ParrotObject
and friends from the actual python source. So I want my
code to work with ParrotObject and ParrotClass for
cross-language stuff, but I don't actually plan to
instantiate them. That's my motivation for wanting one
set of ops and vtable methods.

I like the ideas of having the exact same objects running
in the python VM AND the parrot VM. It means they're
much more likely to be compatible, and more importantly
it saves a TON of work. I might be projecting here, but
I suspect that this is going to be an important stepping
stone to anybody porting an existing language to parrot.
They might eventually use ParrotClass and ParrotObject,
but they can sure get up to speed quicker by wrapping
an existing object system as PMCs.


> >Does this "catalog" have something to do with mapping strings to the
> >appropriate position in the attribute array? "catalog" isn't mentioned
> >anywhere else in the file, and "metadata" only shows up for the
> >instantiate op... So I really don't get this at all.
>
> Yeah. It's unclear, so I'll go fix it.

:)


> >The reason I thought a catalog might map strings to ints is because
> >there doesn't seem to be a vtable method for looking attributes
> >up by string. What's the mechanism for making this happen?
>
> There isn't one.

There should be! :)



> >I also don't understand this opcode:
> >
> >    classoffset Ix, Py, Sz
> >    Returns the offset of the first attribute for class Sz in object Py.
> >
> >What do you do with it once you have it?
>
> That's how a class gets access to its particular set of attributes in
> the big wad 'o attributes attached to the object.


Got it. I definitely see the value here... And seeing this it becomes
very clear that the idea of accessing by  offset vs accessing by string
are very different things. You want offsets so they're fast, but the
tradeoff is that you're exposing the internal structure of the object...
And that's really the main difference between attributes and properties,
right?


There's a parallel here with the calling conventions. For pcc, we say
"you can do whatever you want INSIDE your own little world... But if
you want to play cross-language, then you better follow these
conventions."

We should have the same for objects. If a particular language knows
at compile time what order its attributes are going to be in, then
by all means expose it and get the speed... But it shouldn't break
compatability.

What about this: What if what you're calling "attributes" were
ALWAYS by number? So then when you want it, you can move
fast. (And in that case, you might as just well use the same
opcodes that ManageStructs use)

So if a compiler can get the speed gain, it would use offsets and
move fast, but if it's really dynamic, it could always fall back
on the standard interface of using strings (getprop). Having a
hash over on the side that maps strings to ints isn't going to
slow you down unless you actually use it.



> I think we're actually going to be OK with the split way of doing
> things, if python goes with the property scheme and perl 6/ruby goes
> with the attribute scheme. Properties are *supposed* to be public and
> queryable, while attributes are supposed to be private. Python code
> that accesses per-object thingies will access properties and see all
> the properties stuck on the object by any other piece of python code,
> or any other code that slammed on a property, and that's cool. Python
> code *won't* see the attributes, but again that's OK as it
> *shouldn't*, since it's private.


But surely perl 6 and ruby have SOME public attributes?!
In java it's the convention to say getWhatever() and setWhatever()
but you can still make a public attribute, and i think that should
use getprop.

One last thing... Python (at least the way I envision it) is
going to need to OVERRIDE the getprop vtable method. If you
define __getattr__ or __setattr__  methods for a class, it
will call those instead of just using PMC properties. So
there's at least three different styles now: Parrot props,
Python props, and Parrot attributes... And we haven't
heard from the other language developers yet. Luckily the
first two will look exactly the same from the bytecode's
point of view. I'm just worried about the third. :)

Sincerely,

Michal J Wallace
Sabren Enterprises, Inc.
-------------------------------------
contact: [EMAIL PROTECTED]
hosting: http://www.cornerhost.com/
my site: http://www.withoutane.com/
-------------------------------------

Reply via email to