facets of objects

eugene.leitl at lrz.uni-muenchen.de eugene.leitl at lrz.uni-muenchen.de
Wed Oct 25 14:43:22 EDT 2000


(((slightly edited to foil the spambots)))

From: kragen at pobox dot com (Kragen Sitaker)

In Python, it's really simple to create an object that acts like a
built-in object: a file, a dictionary, a sequence.  You just define the
methods the built-in object implements --- "implement the protocol" ---
and everything that expects the built-in object will then be able to
talk to your object.

Not so in Perl.  You can create objects that act like built-in objects
--- at least in some cases --- but there are several different more or
less clumsy ways of implementing different built-in objects.

In Python, there are magical methods called __getattr__ and
__setattr__, which allow you to create virtual attributes of objects,
so that trying to set an attribute calls __setattr__ instead of setting
the attribute, and trying to read a nonexistent attribute calls
__getattr__ instead of raising an AttributeError.  (Perl has AUTOLOAD,
which does mostly the same thing.)

Both of the Python ways are really simple, but somewhat inadequate.

Your pseudo-file and pseudo-dictionary objects will have attributes
files and dictionaries don't; proving that client code doesn't depend
on those attributes requires looking through the client code at every
variable that could hold an instance of a pseudo-file object and
verifying that the attributes aren't used.

__getattr__ has a more serious problem; it only works for attributes
that don't really exist.  So if your clients use one of the attribute
names you used in your implementation --- presumably not knowing you
used them --- they will get screwed.

In KeyKOS and EROS, it is common for a single object to implement
several different interfaces, such as a read-only interface, a
read-write interface, and a write-only interface; clients holding a
capability to one interface should not automatically be able to get
capabilities to other interfaces, although some interfaces will have
methods that allow a client to request capabilities to other interfaces
to the same object.

All of these problems have a solution in common, I think: "facets".  A
"facet" is a mapping of selectors, such as method or attribute names or
EROS order codes, into attributes of the object; it can be used
anywhere the object can.  Since most kinds of objects don't need
multiple facets, you shouldn't have to do extra work just to use a
language that implements facets; you should only have to do extra work
when you want to define or use a new facet.

Here's a pure-Python implementation that shows what the interface to
facet functionality could look like.  It works insofar as the names you
specify get mapped correctly; it's broken insofar as the Facet objects
it creates still have four object attributes and five class attributes
accessible from any Facet object.  I think I could make it work in C.

class Facet:
    def __init__(self, object, dict, getattr=None, setattr=None):
        self.__object = object
        self.__dict = dict
        self.__getattr = getattr
        self.__setattr = setattr
    def __getattr__(self, attrname):
        if self.__getattr is not None:
            return self.__getattr(self.__object, attrname)
        elif self.__dict.has_key(attrname):
            return getattr(self.__object, self.__dict[attrname])
        else:
            raise AttributeError, attrname
    def __setattr__(self, attrname, value):
        if attrname in ('_Facet__object', '_Facet__dict', '_Facet__getattr',
            '_Facet__setattr'):
            self.__dict__[attrname] = value
        elif self.__setattr is not None:
            return self.__setattr(self.__object, attrname, value)
        elif self.__dict.has_key(attrname):
            return setattr(self.__object, self.__dict[attrname], value)
        else:
            raise AttributeError, attrname

-- 
<kragen at pobox dot com>       Kragen Sitaker     <http://www.pobox.com/~kragen/>
Perilous to all of us are the devices of an art deeper than we ourselves
possess.
                -- Gandalf the Grey [J.R.R. Tolkien, "Lord of the Rings"]


-- 
Unsubscribes to kragen-hacks-unsubscribe at kragen.dnaco.net; public followups to
kragen-discuss at kragen.dnaco.net.  Hacks posted to this list are in the
public domain, unless otherwise specified; I hereby disclaim any intellectual-
property interest in hacks posted here without a copyright notice.




More information about the Python-list mailing list