[melbourne-pug] Coding idiom

Maurice Ling mauriceling at acm.org
Wed May 10 01:28:14 CEST 2006


Bill Birch wrote:

>On Tue, 9 May 2006 09:30 am, Justin Warren wrote:
>  
>
>>Today 09:30:14 am
>>
>>On Mon, 2006-05-08 at 23:23 +1000, Bill Birch wrote:
>>    
>>
>>>On Fri, 5 May 2006 10:57 am, Maurice Ling wrote:
>>>      
>>>
>>>>I am hoping that Bill's type system is able to strike a middle ground
>>>>on this, allowing developers to define their own coding conventions
>>>>which is mappable to a standard type system as metaknowledge, or
>>>>something like that.
>>>>        
>>>>
>>>Hi,
>>>
>>>A type system would help reason about the code. There's been various
>>>proposals to add "interfaces" a la Java to Python. These have merit to
>>>solve this issue. The technique is to first define an interface or
>>>interfaces, then the implementation class methods or attributes that are
>>>not in in the interfaces are effectively private. By declaring interfaces
>>>you are publically committing to honour some methods, but caveat user on
>>>the others.  Because the interface is separated you don't have the issues
>>>with underscores in names. The type system just allows you to capture the
>>>method signatures and have code to introspect them at runtime.
>>>      
>>>
>>This is something I don't really understand as I don't have the
>>background; I chose engineering. :) Could you possibly explain it? There
>>may be others on the list who are interested in some CS fundamentals,
>>too. Not understanding it well enough is a large contributor to my
>>apprehension.
>>    
>>
>Me too, I chose engineering. I just read a lot ;-)
>
>OK - Here's an explanation: 
>
>Type systems are just meta-data, that is data about data. The int object in 
>Python is just an object like any other, except it captures the thought "all 
>objects which are integers".  Type theory is based on set theory. So maths 
>people say that a type is just a set. So int is the set of all objects which 
>are integers. And yes it could be infinite.  So when I said that a type 
>system helps you reason about code, I mean that when you layer types onto 
>each other they begin to look like declarative rules. And when you add code 
>which can use the type objects it can make deductions about the programs. 
>This is how type inferencing works. The languages have rich internal type 
>systems which the compilers use to do fancy deductions about types.
>
>Interfaces were created as a way of describing classes without showing how 
>they were implemented. C++ has abstract classes and multiple inheritance. 
>Java has interfaces as a way of allowing objects to have a kind of multiple 
>inheritance. There are also hundreds of "Interface Definition 
>Languages" (IDLs) for defining distributed procedure calling. DCE, CORBA, 
>SOAP all have them. All of them provide just the class definition without any 
>procedural code:
>
>interface Shape:
>	def draw(x: int, y: int)
>	def moveTo(x, int, y: int)
>	def area() -> float
>
>An interface just describes the outside surface of the object. There are no 
>innards.
>
>So if you can declare that you are abiding by that interface:
>
>class Square( implements(Shape) ):
>	def __init__(self, ...):
>		...
>	def draw(x: int, y: int):
>		...
>And an IDE or  type checker can make sure you -do- implement all the required 
>methods. Likewise, if someone is writing generic code they can limit the 
>number of possibilities by constraining input arguments to only allow objects 
>which conform to an interface:
>
>def drawAlotOfShapes(collection: list[Shape]):
>	for s in collection:
>		s.draw()
>
>Interfaces allow you to say "I look like a Shape" , whereas class inheritance 
>says " I am constructed from a Shape".
>
>People using Python don't need interfaces to be able to call methods, but in 
>large bodies of code (like Zope) it helps humans to understand how to 
>maintain the code if there is a description of the significant methods 
>required to plug one class into another. This is why Zope added their own 
>interfaces. 
>
>Interfaces are a way of saying to the user of your code which bits they need 
>to care about.  So what I meant was that if you are using interfaces to 
>document your classes, then there is less need to adopt concepts like 
>'private'. If all you know about is the interface, you don't see the guts. 
>  
>Python is at a cross-roads in its development, because in Python-3000 it's 
>likely that there will be a way to annotate functions with types, and hence 
>there will be some easier way to implement interfaces. However the Python 
>community needs to decide if they are going to have a type system that works 
>with duck typing like Haskell, or one that is like C++/Java. 
>
>The two camps are "structural subtyping" and "nominative subtyping". 
>nominative subtyping works off labels attached to the objects. If you are 
>nominative you simply look at the label on an object to  find out what it is. 
>So if there is a thing with a label stuck to it saying "I am a duck." you 
>just assume it is one.  If you are structural you actually perform a deep 
>analysis of the object and deduce its type based on what you find and prior 
>declarations. So if you see that something has feathers, wings, a bill and 
>makes a quacking sound you assume it is a duck. Even if it has a note stuck 
>to it saying "I am a banana.".
>
>Python currently uses duck typing  (aka no typing), it's like LISP in that 
>way. Call a function, see what it does. So IMHO if Python is to be expanded 
>to have Interfaces and more complex types, then it needs to support 
>structural subtyping -and- nominative typing.
>
>Although Python does have nominative labels, __class__, __bases__, they don't 
>prevent classes with different names working in the same role. e.g.
>
>class A(object):
>    def callMe(self):
>	print 'callMe'
>
>class B(object):
>   def callMe(self):
>        print 'callMe'
>
>def useIt(x):
>	x.callMe()
>
>useIt(A()) # no error
>useIt(B()) # no error
>
>Although class A and B have no relationship to each other they are 
>'plug-compatible'. They are structural equivalents and hence useIt() can call 
>either. This would fail in C++ or Java since A and B would have to inherit 
>from an interface of base class.
>
>The goal is to codify the structural interface in an obvious way:
>
>interface IcanBeCalled:
>   def callMe()
>
>  
>
The explanation that Java developers gave for having interface is that 
Java only accepts single inheritance, which can be a problem. For 
example, Java threads typically inherits from Thread class, which 
contains the methods for multithreading. However, this means that your 
class (ie, circles) cannot be derived from another suitable parent class 
(ie, shapes). So, an interface "Runnable" is used. In fact, Thread class 
implements Runnable to mark it as multithreadable. Now, my Circles class 
can be derived from Shapes class and implements Runnable for multithreading.

Python does not have this issue.

Nevertheless, I concur with Bill about interfaces (ie, class 
declarations without innards). Sometimes in my work, I use "abstract" 
classes to mark out crucial interfaces (ie, an engine class should have 
the following methods implemented) so that module switching (in the case 
of plug ins) can happen at runtime. May not have any real protection or 
safeguard value but it sure has documentation value. For example, the 
interface class describes what the methods should do (the requirements), 
and the implementation class (implementing the interface) describes how 
the methods are implemented in accordance to the requirement.

maurice


More information about the melbourne-pug mailing list