prototyping good OOdesign in Python?

Ken Seehof kseehof at neuralintegrator.com
Sat Jun 1 22:04:50 CEST 2002


> Maybe this was already discussed, but I'd liked to raise this topic again.
>
> Python has superb OOProgramming support. Lets not dispute this for a
> moment. Now let's consider that we need to make well-designed OOP solution
> first prototyped in Python.
>
> What troubles are there? Python is too dynamic and all that. And all
> those nifty features need to be translated properly into, say, C++.
>
> Recently I encountered the following piece of code
> (from Arts++ project):
>
> //================================================================
> ===========
> //  Copyright Notice
> //
> //  By accessing this software, arts++, you are duly informed
> //  of and agree to be bound by the conditions described below in this
> //  notice:
> //
> //  This software product, arts++, is developed by Daniel W. McRobb, and
> //  copyrighted(C) 1998 by the University of California, San Diego
> //  (UCSD), with all rights reserved.  UCSD administers the CAIDA grant,
> //  NCR-9711092, under which part of this code was developed.
> //
> //  There is no charge for arts++ software.  You can redistribute it
> //  and/or modify it under the terms of the GNU Lesser General Public
> //  License, Version 2.1, February 1999, which is incorporated by
> //  reference herein.
> //
> //  arts++ is distributed WITHOUT ANY WARRANTY, IMPLIED OR EXPRESS, OF
> //  MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE or that the use
> //  of it will not infringe on any third party's intellectual
> //  property rights.
> //
> //  You should have received a copy of the GNU Lesser General Public
> //  License along with arts++.  Copies can also be obtained from:
> //
> //    http://www.gnu.org/copyleft/lesser.html
> //
> //  or by writing to:
> //
> //  Free Software Foundation, Inc.
> //  59 Temple Place, Suite 330
> //  Boston, MA 02111-1307
> //  USA
> //
> //  Or contact:
> //
> //    info at caida.org
> //================================================================
> ===========
>
> //  constructor
>
> ............skip
>
> Arts::Arts()
> {
>   this->_data._ipPath = (ArtsIpPathData *)0;
>   this->_data._asMatrix = (ArtsAsMatrixData *)0;
>   this->_data._netMatrix = (ArtsNetMatrixData *)0;
>   this->_data._portTable = (ArtsPortTableData *)0;
>   this->_data._portMatrix = (ArtsPortMatrixData *)0;
>   this->_data._protocolTable = (ArtsProtocolTableData *)0;
>   this->_data._selectedPortTable = (ArtsSelectedPortTableData *)0;
>   this->_data._interfaceMatrix = (ArtsInterfaceMatrixData *)0;
>   this->_data._nextHopTable = (ArtsNextHopTableData *)0;
>   this->_data._bgp4RouteTable = (ArtsBgp4RouteTableData *)0;
>   this->_data._rttTimeSeriesTable = (ArtsRttTimeSeriesTableData *)0;
>   this->_data._tosTable = (ArtsTosTableData *)0;
>
>   #ifndef NDEBUG
>     ++_numObjects;
>   #endif
> }
>
> Arts::Arts(const Arts & arts)
> {
>   this->_header = arts.Header();
>   this->_attributes = arts.Attributes();
>
>   switch (this->_header.Identifier()) {
>     case artsC_OBJECT_IP_PATH:
>       this->_data._ipPath = new ArtsIpPathData;
>       assert(this->_data._ipPath != (ArtsIpPathData *)0);
>       *(this->_data._ipPath) = *(arts.IpPathData());
>       break;
>
>     case artsC_OBJECT_AS_MATRIX:
>       this->_data._asMatrix = new ArtsAsMatrixData;
>       assert(this->_data._asMatrix != (ArtsAsMatrixData *)0);
>       *(this->_data._asMatrix) = *(arts.AsMatrixData());
>       break;
>
>     case artsC_OBJECT_NET:
>       this->_data._netMatrix = new ArtsNetMatrixData;
>       assert(this->_data._netMatrix != (ArtsNetMatrixData *)0);
>       *(this->_data._netMatrix) = *(arts.NetMatrixData());
>       break;
>
>     case artsC_OBJECT_PORT:
>       this->_data._portTable = new ArtsPortTableData;
>       assert(this->_data._portTable != (ArtsPortTableData *)0);
>       *(this->_data._portTable) = *(arts.PortTableData());
>       break;
>
>     case artsC_OBJECT_SELECTED_PORT:
>       this->_data._selectedPortTable = new ArtsSelectedPortTableData;
>       assert(this->_data._selectedPortTable !=
> (ArtsSelectedPortTableData *)0);
>       *(this->_data._selectedPortTable) = *(arts.SelectedPortTableData());
>       break;
>
>     case artsC_OBJECT_PORT_MATRIX:
>       this->_data._portMatrix = new ArtsPortMatrixData;
>       assert(this->_data._portMatrix != (ArtsPortMatrixData *)0);
>       *(this->_data._portMatrix) = *(arts.PortMatrixData());
>       break;
>
>     case artsC_OBJECT_PROTO:
>       this->_data._protocolTable = new ArtsProtocolTableData;
>       assert(this->_data._protocolTable != (ArtsProtocolTableData *)0);
>       *(this->_data._protocolTable) = *(arts.ProtocolTableData());
>       break;
>
>     case artsC_OBJECT_TOS:
>       this->_data._tosTable = new ArtsTosTableData;
>       assert(this->_data._tosTable != (ArtsTosTableData *)0);
>       *(this->_data._tosTable) = *(arts.TosTableData());
>       break;
>
>     case artsC_OBJECT_INTERFACE_MATRIX:
>       this->_data._interfaceMatrix = new ArtsInterfaceMatrixData;
>       assert(this->_data._interfaceMatrix !=
> (ArtsInterfaceMatrixData *)0);
>       *(this->_data._interfaceMatrix) = *(arts.InterfaceMatrixData());
>       break;
>
>     case artsC_OBJECT_NEXT_HOP:
>       this->_data._nextHopTable = new ArtsNextHopTableData;
>       assert(this->_data._nextHopTable != (ArtsNextHopTableData *)0);
>       *(this->_data._nextHopTable) = *(arts.NextHopTableData());
>       break;
>
>     case artsC_OBJECT_BGP4:
>       this->_data._bgp4RouteTable = new ArtsBgp4RouteTableData;
>       assert(this->_data._bgp4RouteTable != (ArtsBgp4RouteTableData *)0);
>       *(this->_data._bgp4RouteTable) = *(arts.Bgp4RouteTableData());
>       break;
>
>     case artsC_OBJECT_RTT_TIME_SERIES:
>       this->_data._rttTimeSeriesTable = new ArtsRttTimeSeriesTableData;
>       assert(this->_data._rttTimeSeriesTable !=
> (ArtsRttTimeSeriesTableData *)0);
>       *(this->_data._rttTimeSeriesTable) =
> *(arts.RttTimeSeriesTableData());
>       break;
>
>     default:
>       break;
>   }
>
>   #ifndef NDEBUG
>     ++_numObjects;
>   #endif
> }
>
> ..........skip the rest of file - there are 2-3 more similar
> .......... switch-constructs.
>
> ------------------------------------------------------------
>
> This code looks like... automatically generated. Rather than manually
> written. I do not know why it was written in C++ at all. Of course, I
> imagine 2-3 variants of how to refactor it if I were writing the code
> in Python. I am pretty sure there were no select statement (switches)
> in Python code, because that is what polymorphism is about.
>
> But then again, translating back to C++ could be difficult. The
> mentioned example is all about reading a specially formatted binary
> file to produce certain slices of information. And for each
> class it uses separate .cc/.hh file! While all the difference
> between different classes - structure of corresponding data entries.
>
> My approach in this case could be one resource file, with format
> specification (like DTD). Plus one univarsal class to handle big
> binary file according to "DTD"). Plus maybe separate resource file
> with data query specifications. And it could be at most 80 Kb Python
> project, not that monster Arts++ is in both source and binary forms...
>
> Well, if you still follow this thread, the question is - how well
> Python could serve as an ARCHITECTURAL prototype if it has too rich
> OOP facilities? That is, is Python of help when trying to
> prototype certain design? Developing in C++ looks so unnecessary hard
> after things were done in Python...
> Or, it may be put this way: what discipline a Python programmer must
> obey to allow it's prototype to be conveniently rewriten in C++?
> The above thoughts aren't probably well-formed. But I hope
> my concern is understood.
>
>
> Sincerely yours, Roman Suzi

I agree with what you are saying.  Here's my approach :-)

0. Write a project schedule for management; something like this:
   1. Prototype in python
   2. Convert to C++
1. Prototype in python
2. Give a nice demo, and convince management to skip step 2
3. Re-implement a few cpu intensive classes in C++

Since most of the code never /actually/ gets rewritten in C++,
the need for special C++ "discipline" in the python code goes
away.  Weeks are slashed from the schedule, and the program is
more maintainable.

Another nice advantage is that the python programmer gets to ask
for a raise, and has excellent job security!

There may be a few oddball examples of projects that actually
need to end up written in C++ after prototyping in python, but
for the most part, the most common reason to target C++ is to
alleviate fear of the unknown.  (Hmm, is this also why people,
(including myself), still buy from Microsoft? :-)

- Ken Seehof






More information about the Python-list mailing list