[Zope3-dev] Notations for paths

Phillip J. Eby pje@telecommunity.com
Thu, 19 Dec 2002 13:01:47 -0500


At 06:15 PM 12/19/02 +0100, Florent Guillaume wrote:
>On Thu, 2002-12-19 at 18:01, Phillip J. Eby wrote:
> > >So, there are special functions for correctly converting between the
> > >string form and the tuple form.
> > >
> > >I've had to correct a number of bugs where the naive conversion had been
> > >used. These bugs were somewhat tricky to track down, becuase the effects
> > >didn't point to this as the obvious cause.
> >
> > I think you missed my point.  This is *precisely* why Zope shouldn't 
> use an
> > unencapsulated representation like tuples for this in the first place!
> >
> > Nobody should be doing any conversions directly.  There should be a
> > location class, and only strings or instances of the location class should
> > be allowed.  Code which uses locations should invoke the location
> > constructor on any input, to ensure that strings become locations.
>
>Why go to those lengths when we can have a perfectly effective location
>as a tuple of names in trivial bijection with a string?

What lengths?  Having a class?  Calling it?  Seems to me like very little 
work to ensure correct behavior.  Heck, I'll write the class myself, if you 
want.  :)

The point is that it's bad design to:

1) shuffle around tuples for something that *isn't* a tuple

2) Create functions for manipulating tuples that people are supposed to use 
(but won't, because it'll seem too simple to just "do it themselves" and 
manipulate the tuple directly)

Now that it has become clear that it doesn't work, the simple and obvious 
solution is to subclass tuple, i.e.:


from types import StringTypes

class ZopeLocation(tuple):

     def __new__(klass, stringOrLocation):

         if isinstance(stringOrLocation,klass):
             return stringOrLocation

         if isinstance(stringOrLocation,StringTypes):

                path = stringOrLocation.split('/')

                if not filter(None,path):
                    # string was all '/'...  remove one empty element
                    path.pop()

                return super(ZopeLocation,klass).__new__(klass,path)

         raise TypeError("Not a string or location", stringOrLocation)

     def __str__(self):
         path = list(self):
         if not filter(None,path):
             # all empty parts, add one extra
             path.append('')
         return '/'.join(path)

     def traverse(self, start):
         # XXX do something useful...

     def commonPrefix(self,other):
         # XXX do something useful...

     # etc...

Now any other functionality associated with locations can be added to the 
class.  And, if it's decided the string format or the internal 
representation needs to be different for some reason, why then it can be 
changed in one place.  And, because nobody knows it's a tuple unless they 
read the code, they won't go messing with it and spreading bugs all over 
the place.  (Even if they do know it's a tuple, my example specifically 
disallows conversion from tuples.)

If y'all think path manipulation problems are widespread *now*, just wait 
till non-core Zope developers get a hold of it.