[Python-3000] Abilities / Interfaces

Dave Anderson python3000 at davious.org
Thu Nov 23 13:46:34 CET 2006


Proposal Summary
================

Add 2 new keywords: implements, implement
(alternatively, implements and implement can be implemented as object 
level functions)
Add new built-in function: interface
Add new object level function: does_implement

(with minor corrections in Implementation of Interfaces (Implements and 
Implement) section)

Interfaces
==========

There is a fight between using classes/types for dispatch verses class 
methods for dispatch.  There is a fight between declaring class 
compatibility and declaring method compatibility.

We see this explicit declaration in Phillip's
     defop iter(self):

versus method checking

We should unify these concepts by allowing them to mix in an interface 
definition:

Interfaces, here, are a set of class types, class methods/attributes, 
and strings

* Class/Type: Can be built-in or user-defined
   when Class2 declares it implements Class1, we will presume
   the class will support anything Class1 will support, but will only 
crash on a call to a method Class1 has, but Class2 does not
* Class Method/Attribute: Can be from a built-in object or be 
user-defined class
   when Class2 declares it implements a Class1.amethod, we will
   presume the class as a method amethod, but will only crash on a call 
to Class2.amethod if Class2.amethod is not defined.
* String: Indicates a method or attribute with that name, introspection 
is used to see if a Class implements this

iter_interface = interface(iter)  # class-based interface
file_open_close_inter = interface(file.open, file.close) # method interface
# here is an interface looking for both a class and some methods to be 
'implemented'
iter_file_open_close_inter = interface(iter, file.open, file.close)

Implementation of Interfaces (Implements and Implement)
=======================================================

In the common case, a class already implements another class behavior 
and we just need to say that.
Other times, we want to adapt or use a special method in a certain context.

Implement and Implement:
* Implements: Declares pre-existing compatability
   It is a list of classes/types and class methods/attributes

   when Class2 declares it implements Class1, we will presume
   the class will support anything Class1 will support, but will
   only crash on a call to a method Class1 has, but Class2 does not

   when Class2 declares it implements a Class1.amethod, we will
   presume the class as a method amethod, but will only crash
   on a call to Class2.amethod if Class2.amethod is not defined.

* Implement: Indicates special method-help via adaptation or a different 
method.
   The keyword is used to define a function that acts as a class/type 
adapter or special function.

   When Class2 uses an implement to associate a class/type or
   method/attribute with a function definition, that function should
   called to which effectively adapts the Class2 obj when the context is
   'implement Class' or runs a specially defined method when the context
    is 'implement method'.

Class's declared to be implemented are presumed to have the full method 
set of the class, those reducing the need for extensive method checking 
at the adult-allowable risk of someone not completely implementing the 
classes methods.  (Of course, we now have implementation declaration 
inspection of a sort.)

Dispatching by Interface and Declared Implementation
=====================================================

the example Bar class (following these dispatching examples) should be 
able to be dispatched by
* methods looking for a iter, Foo, SomeOtherClass, YetAnotherClass instances
   example: def funct(iter_var: iter):

* methods looking for a method of those classes
   example: def funct(var_that_implements_foo_or_declares_a_foo_method: 
Foo.method):

* methods looking for methods file.open, file.close, AnotherClass.close
   example: def funct(var_with_a_method_like_file_open: file.open):

* methods looking for just method of with a particular name
   example: def funct(var_with_a_method_called_open: "open"):

the dispatch need not be based on a singular type or method
  (see below for those multi-condition interface examples)

also, these dispatch functions can be class functions
  example def funct(self, var_with_a_file_open_meth: file.open):


Example of Using Implements and Implement
=========================================

class Bar(Foo):
"""based on the declarations that follow class is taken as iter, Foo, 
and SomeOtherClass without method introspection (return of self for 
these is implicit) methods open and close are understood to be file like 
methods. An adaption functionality is available in the declaration 
implement AnotherClass and special method as a particular class is 
available in the declaration implement
YetAnotherClass.method."""
     # new keyword implements
     implements iter, SomeOtherClass, file.open, file.close

     # new keyword implement: for class adaptation
     implement AnotherClass(self):
         return transform_to_yac(self)

     implement YetAnotherClass.open(self, var):
		return different_open_function(self, var)

     # presumed for file.open
     def open(self):

     # presumed for file.close
     def close(self):

     [implementing iter functions not shown]


Interface objects, including multiple object apis
===================================================
* use of new standard interface function
* allows multiple interface apis to be combined

foo_interface = interface(Foo)
iter_interface = interface(iter)
file_open_close_interface = interface(file.open, file.close)
any_open_close_interface = interface("open", "close")
iter_file_open_close_inter = interface(iter, file_open_close_interface)

def funct(foo_var: Foo):
.. equivalent to ..
def funct(foo_var: foo_interface):

def funct(iter_var: iter):
.. equivalent to ..
def funct(iter_var: iter_interface):

def funct(file_like_var: file.open, file.close):
.. equivalent to ..
def funct(file_like_var: file_open_close_interface):

def funct(method_abilities_var: "open", "close"):
.. equivalent to ..
def funct(method_abilities_var: just_open_close_methods_interface):

def funct(method_abilities_var: iter, file.open, file.close):
.. equivalent to ..
def funct(method_abilities_var: iter_file_open_close_inter):


does_implement
==============

* does_implement: a boolean function that at the object level that
   returns true if the object has declared that it implements an 
interface object

if obj.does_implement(iter):

if obj.does_implement(Class1):

if obj.does_implement(interface_obj):

Implementing Interfaces without the keywords Implements, Implement
==================================================================
Class2.implements(iter)

Class2.implements(Class1)

Class2.implements(interface_obj)

Class2.implements(file.open)

Class2.implements(iter, Class1, interface_obj, file.open)

Class2.implement(Class1, transform_function_def)

Class2.implement(Class1.method, function_def)

Dispatching Issues
==================

There will have to be some way to decide which declarations are chosen
ahead of others, but I haven't thought about that too much.. we'd
probably look at the order of the objects in the implements statement.

The last issue I have in my head is Guido's issue
 > This doesn't do anything for other generic functions that might also
 > conceivably work with C. Phillip addresses that by proposing help
 > functions that do a bunch of these bindings at once, and by noticing
 > that if you just use the standard library and generic functions, the
 > default implementation might just work.

But, it think those bindings could be generated with some *implements*
declarations inside of standard objects like Iterable - Collection -
Sequence - MutableSequence - list to each other.  These declarations 
will be inherited by those object which declare they implement them.

With this syntax, dispatch functions would seamlessly integrate with the 
current python language, the absence of any interface in a function def 
would be the python language as it works now, by defaulting to the 
lowest and most-likely only "dispatching" function.


More information about the Python-3000 mailing list