[SAGA-RG] Python Bindings: method overloading

Andre Merzky andre at merzky.net
Tue Feb 12 16:28:57 EST 2013


Hi all,

we have been rethinking the method overloading problem for the Python
bindings again.  As a reminder, this is the problem:

  - A namespace entry has a method 'entry.copy (tgt, flags)'

  - A namespace directory inherits from the entry, and adds another
copy method: 'dir.copy (src, tgt, flags)'

  - Python though does not do method overloading, but only method
*overwriting*.  For that reasons, based on a suggestion of Paul, we
renamed the conflicting methods on entry level with a '_self' postfix:
'entry.copy_self (tgt, flags)'.


It seems we found a way to implement real method overloading thouhg --
and since the code overhead is not too bad, we would like to propose
that mechanism for the SAGA Python bindings.

First, these are the methods we are talking about, sorted by signature types:

    def copy      (self,      tgt, flags=None, ttype=None) : pass
    def copy      (self, src, tgt, flags=None, ttype=None) : pass
    def link      (self,      tgt, flags=None, ttype=None) : pass
    def link      (self, src, tgt, flags=None, ttype=None) : pass
    def move      (self,      tgt, flags=None, ttype=None) : pass
    def move      (self, src, tgt, flags=None, ttype=None) : pass

    def get_size  (self,           flags=None, ttype=None) : pass
    def get_size  (self,      tgt, flags=None, ttype=None) : pass
    def remove    (self,           flags=None, ttype=None) : pass
    def remove    (self,      tgt, flags=None, ttype=None) : pass

    def is_dir    (self,                       ttype=None) : pass
    def is_dir    (self,      tgt,             ttype=None) : pass
    def is_entry  (self,                       ttype=None) : pass
    def is_entry  (self,      tgt,             ttype=None) : pass
    def is_file   (self,                       ttype=None) : pass
    def is_file   (self,      tgt,             ttype=None) : pass
    def is_link   (self,                       ttype=None) : pass
    def is_link   (self,      tgt,             ttype=None) : pass
    def read_link (self,                       ttype=None) : pass
    def read_link (self,      tgt,             ttype=None) : pass

So, the differences are never in the keyword args (kwargs), but always
in the args w/o keyword.  The kwargs are always flags, i.e. integers,
or enums, which we can also define as integers.

As said: Python does not allow method overloading, only method
replacement.  But it *does* allow for variable parameter lists (*args,
**kwargs).  We can deselect the int types from the args, and count the
remaining arguments:

  d = {'src' : 'src', 'tgt' : 'tgt', 'flags' : 3, 'ttype' : 2}
  l = list (v for v in d.values () if not isinstance (v, int))

  print len(l) # 2


So, one can code the following:


  class ns.entry :

  # def copy  (self,        tgt, flags=None, ttype=None) : pass
  # def copy  (self, src,   tgt, flags=None, ttype=None) : pass
    def copy  (self,      *args,               **kwargs) :

      non_int_args = args + list (v  for v in kwargs.values () \
                                  if not v == None and not isinstance (v, int))
      if  len (non_int_args) == 2 :
          return self._adaptor.copy_self (args, kwargs)
      if  len (non_int_args) == 3 :
          return self._adaptor.copy      (args, kwargs)

      raise BadParameter ("signature mismatch: copy (url, [url], flags, ttype)")


All further signature checks are automatically done on CPI / adaptor
level -- although one could here add type checking for flags and
ttypes at this point.

We think this makes the API significantly cleaner and easier to use --
so please let us know what you think...

Best, Andre.


-- 
There are only two hard things in Computer Science: cache invalidation
and naming things.

-- Phil Karlton


More information about the saga-rg mailing list