Unification of Methods and Functions

David MacQuigg dmq at gain.com
Thu May 13 16:54:01 EDT 2004


I'm beginning to understand what you are saying.  Thanks for hanging
in there.

On 12 May 2004 20:51:20 -0700, moughanj at tcd.ie (James Moughan) wrote:

>David MacQuigg <dmq at gain.com> wrote in message news:<q313a0lroe1uiiu43nkhhnqnbcm4jhgkrk at 4ax.com>...
>> On 10 May 2004 16:53:06 -0700, moughanj at tcd.ie (James Moughan) wrote:
>>
>> >David MacQuigg <dmq at gain.com> wrote in message news:<889t90tdl9o9t25cv5dj6k5rnktuce0jin at 4ax.com>...
>> >> On 8 May 2004 07:07:09 -0700, moughanj at tcd.ie (James Moughan) wrote:
>>
>> < snip topics we have finished >
>>
>> >You are not solving a problem; that's the problem. :)  If there were a
>> >real programming task then it would be more trivial to show why your
>> >object model is broken.
>>
>> I could give you an example from IC Design, but for the course I
>> teach, I chose to use a similar hierarchy based on something everyone
>> would understand - a taxonomy of animals.  Nothing in this example is
>> something you wouldn't find in a real program to model an integrated
>> circuit.  Instead of animal names like Cat, we would have the names of
>> cells in the hierarchy, names like bgref25a.  Instead of a variable to
>> count the number of animals at each level, we might have several
>> variables to track the total current on each of several supply lines.
>> Like the counts in the Animals.py hierarchy, we need the total current
>> to each cell, including all of its subcells.
>
>As far as I understand it, this is fairly different; the way I would
>implement it, each cell would be an instance, not a class.  I would
>have to look at some kind of code/spec to really know, though.  Do you
>have an example of a piece of software were you follow this approach?

Using instances instead of classes is something I hadn't considered.
I could add one line after each class to instantiate it.  I'll have to
play with this a bit, and see if I can come up with a *simple* program
to do the same thing as Animals_2, but using instances.  I don't yet
have the code written for my circuit-design platform, but I can give
you a spec that describes some of the needs I see.

1) We need to represent a hierarchy of cells, typically 5 to 10 levels
deep.
2) Each cell has data associated with it.  Some of this data is a
cummulative total of similar data from all subcells -- total currents,
total chip area, etc.
3) The data for each cell is unique, and it must be displayed in a
format unique to that cell.
4) We need a simple function, show() that can be called for any cell
or no cell at all (just knowing the cell type).  This function should
show the cell data and the data from all cells above it.  In case no
cells of a particular type have been added to the design, the
cummulative data should just show a default value, like zero.

In addition to these functional requirements, we need to make the
program structure as simple as possible, to use as an introduction to
OOP for design engineers who have no CIS background, but have learned
Python up to the point where OOP is introduced.

Robustness and generality are not prime requirements at this point,
although introducing something like _private variables is OK, because
it won't distract from the introduction.

>> I'm sure there are other examples from other specialties.  In
>> accounting, I can imagine a hierarchy of accounts, with a total for
>> each account including all of its subaccounts.  Don't just assume that
>> the problem isn't real because you haven't encountered it in your
>> work.
>
>Sorry, but that's not how you would do an accountancy package in OO. 
>Again each account would be an instance, not a class, otherwise adding
>a new account would require either code modification or metaclass
>hacking.  Instances scope down, and having a count of the sub-accounts
>stored in an object would be OK in my book.  Though you wouldn't need
>to, since the container for the instances would do it for you.

Seems like this is very much like the Animals example.  We create an
instance for each asset, but there is one Asset class which is not an
instance.  You can't transfer funds to the Asset class, only one of
its accounts.  The Asset class, like the Mammal class, keeps data that
is representative of all instances of the class.

>But even this isn't how you would organize an accountancy program. 
>You'd use a database.

That would not work as an example introducing OOP.  It would be like
saying to the students -- You can't understand OOP, so we're not even
going to try.  Just learn this database program, and use it to solve
whatever problems you may encounter.

>>
>> <snip>
>>
>> >If you can't take it below 70 pages and you only have 4 hours... maybe
>> >it's not such a great idea to try this?  I can't see your students
>> >benefiting from what you're proposing to do, if you have so little
>> >time.
>>
>> I think I could do it in 30 pages and 4 hours total ( lecture, lab,
>> and homework ), but not if I need to cover the topics that both Mark
>> Lutz and I consider important to basic OOP in the current version of
>> Python.  The 30 pages assumes the unification of methods and functions
>> that I have proposed.
>>
>
>70 -> 30 because of this?  Really?

I would also cut way back on the "motivational" parts, and a number of
other things that fit well in the current presentation, but are not
necessary in the presentation I have in mind.  My 30 page estimate is
based not on crossing out topics in Learning Python, but on looking at
the 7 pages I have now, and guessing what more I need to add.

One of the best books I've ever read on a complex subject is
Introduction to Quantum Theory by David Park.  The book is split into
two parts: the theory, which is presented in a brief, straightforward,
but unrushed manner; and the examples, which amplify and re-iterate
what is in the theory section.  The first time through, you need to
spend a lot of time reading the examples along with the theory.  Years
later, you can quickly read just the theory section, and it is a real
pleasure.

I think I can present the "theory" of OOP in 7 pages, at a sensible
pace, including everything I think will be needed to write most
programs ( bound and unbound methods, lambdas, static methods, etc. ).
http://ece.arizona.edu/~edatools/Python/Prototypes.doc  Adding
examples and exercisise may take another 25 pages.  Adding
supplementary topics ( multiple inheritance, method resolution order,
some of the techniques you are showing to make classes more versatile
and robust, etc. ) may take another 30 pages.

>Anyway, I guess you know what you have time to do, it being your
>course 'n all. :)
>
>> <snip>
>>
>> >>
>> >> What data are we talking about?  numMammals is specific to Mammal.
>> >> genus is specific to Feline, but *inherited* by instances of a
>> >> subclass like Cat.
>> >
>> >The numAnimals etc... data, which is stored in Animals but gets
>> >arbitrarily altered by the actions of subclasses of Animal, and
>> >therefore is not specific to animal; it doesn't represent the state of
>> >the Animal class or of Animal objects, but of a whole bunch of
>> >subclasses of Animal.
>>
>> The total current to an IC is the sum of the currents to all of its
>> subcircuits.  That current is a single number, for example, 35
>> microamps.  It has a name "Iss".  Iss is a characteristic of the IC
>> which appears in data sheets, etc.  It is a variable representing the
>> state of the entire IC.  It does not represent the state of any
>> subcircuit in the IC, even though it gets "altered" whenever one of
>> those subcircuit currents changes.
>
>So the IC is an instance which stores or accesses data about the
>instances which it contains, i.e. circuit elements; not a class which
>you sub-class to get subcircuit elements.  I'm discussing classes and
>class heirarchies, not instance heirarchies.

I was also assuming a class hierarchy.  The idea of a hierarchy of
instances is new to me.  I guess I'll need an example to know what you
are talking about.

>> Looks like this whole argument comes down to what we mean by the word
>> "specific".  Let's drop it and focus on the more interesting topics in
>> this thread.
>
>From here, it looks like the problem is the difference between an
>instance and a class?

???

>> >>
>> >> These are normal programming errors that can occur in any program, no
>> >> matter how well structured.  I don't see how the specific structure of
>> >> Animals.py encourages these errors.
>> >
>> >Imagine if your structure had been implemented as one of the basic
>> >structures of, say, Java.  That is, some static data in the Object
>> >class stores state for all the subclasses of Object.  Now, someone
>> >coming along and innocently creating a class can break Object -
>> >meaning that may break anything with a dependency on Object, which is
>> >the entire system.  So I write a nice GUI widget and bang! by some
>> >bizzare twist it breaks my program somewhere else because of an error
>> >in, say, the StringBuffer class.  This is analagous to what you are
>> >implementing here.
>>
>> I'll need an example to see how these general worries can affect the
>> Animals_2 hierarchy.  What I see is quite robust.  I added a Feline
>> class between Mammal and Cat, and I had to change only two lines in
>> the Cat class.  ( And I could avoid even that if I had used a "super"
>> call instead of a direct call to the Mammal functions.)
>
>And if someone unfamiliar with the code neglects to call the
>superclass initializer when they create a new animal, then the code
>will break in unpredictable places.  Not calling the superclass is a
>common problem - but easily fixable, *providing* the effects show up
>in the subclass, and not at some other random place in the heirarchy.

Adding a call to a superclass __init__ is a common pattern in the
examples I've seen.  See the section "Calling Superclass Constructors"
starting on page 321 in Learning Python, 2nd ed.

We need to make a distinction between users and programmers in our
expectations of what kind of errors they will make.  Users only need
to *read* a class definition and understand what it does.  Programmers
are the group that needs to remember to add a call to the superclass
when they write a new class.

I am a user of the Qt Toolkit, but I would not attempt to add a class
to their existing hierarchy.  Nor would I expect Trolltech to provide
me with some kind of robust class-generating function that was
guaranteed to generate an error-free class at any point in their
hierarchy I might chose to insert it.

>> >While errors are always going to happen, OOP calls on some conventions
>> >to minimize them.  The most absolutely vital of these is that it's
>> >clear what can break what.  Generally I should never be able to break
>> >a subsystem by breaking it's wrapper; definitely I should never be
>> >able to break a superclass by breaking it's subclass; and I
>> >*certainly* shouldn't be able to break a part of the system by
>> >changing something unconnected to it.  The whole of OOP derives, more
>> >or less directly, from these principles.  Expressions like 'A is a
>> >part/type of B' derive from this philosophy, not the other way around.
>>
>> Sounds good.
>>
>> >Your program breaks with this concept.  It allows an event in Cat to
>> >affect data in Mammal and in Animal, which also has knock-on effects
>> >for every other subclass of these.  Therefore it is bad object
>> >oriented programming.
>>
>> We are modeling the real world here.  When you add a lion to a zoo,
>> you add one to the count of all animals.
>
>When you add a lion to a zoo, you add one entry in the lion table of
>your database.  When you want to know the number of animals in the
>zoo, the database query counts the number of entries in all of the
>animal tables.  *Real* databases are built that way because of
>experience; repetition of data invariably causes out-of-synch
>problems.

I think the database problem is different than our Animals example.
With a database, you typically have many users directly changing the
data over a long period of time when errors can accumulate.  Maybe
some user runs a "transaction" script to debit one account and credit
another, but his line goes down before the second part completes.  So
it makes sense in this case to store only the primitive data, and
accept the overhead of recalculating everything else from that data
whenever it is needed.

>I worked on a project a couple of years ago to port a legacy database
>into MySQL, and it was made damned close to impossible by this sort of
>thinking; how the heck do you port a database which has had it's
>shortcomings patched over to the point where it depends on the
>inconsistent results for it's output? :-\
>
>> When you add 2 microamps to
>> the core currents in a bandgap voltage reference, you add that same 2
>> microamps to the total supply current.
>>
>
>Again, I'd be inclined to handle this problem at the instance level,
>not the class level.
>
>> I'm no expert in OOP, but what I have seen so far is not near as clear
>> in structure as the origninal Animals_2 example.
>>
>
>When you have to troll through a 20K line program where the
>functionality for a single subsystem is scattered through multiple
>classes in a heirarchy, it puts a really different perspective on what
>'clear structure' is.  Likewise, when everything is modularized
>explicitly and you can alter a complex system which you barely
>understand to include completely new core functionality in an hour or
>two of work.

I would expect a Python programmer seeing the Animals_2 example for
the first time, could add a class between Feline and Mammal by the end
of an hour, and be quite confident that nothing was broken.  I studied
your example for two hours, and I still don't understand it well
enough to make some basic changes.

>> >It takes us back to the days before even structured programming, when
>> >no-one ever had any idea what the effects of altering or adding a
>> >piece of code would be.
>> >
>> >It is therefore not a good teaching example. :)
>>
>> I'll need to see something better before I abandon the curent example.
>> The problem may be our expectations of OOP.  I see classes as modeling
>> the real world, including variables that are altered by changes in
>> subclasses.  You seem to have some computer science notion of what a
>> class should be.  I'm not saying its wrong, but unless it helps me
>> solve my real-world problems, in a better way than what I am doing
>> now, I won't use it.
>
>You're right, I don't give a damn whether classes model the real
>world; what matters, in general order of preference, is:
>
>- Robustness
>- Maintainability
>- Programmer time
>- Efficiency

This is a good set of priorities for a production program.  For
teaching OOP, I would say clarity is the over-riding concern.

>I will sell any theoretical principle to the salt mines for those. 
>'Classes-model-the-real-world' is an abstract theory, an evolutionary
>holdover from when OO was the Next Big Thing in AI.  If it leads you
>to design a non-robust, hard to maintain system then, in my book, it
>gets dropped.
>
>> I'm reminded of the criticism Linus Torvalds got when he first
>> published Linux.  The academic community thought it was the worst,
>> most fundamentally flawed design they had ever seen.  It did not fit
>> some expectation they had that a "microkernel" architecture was the
>> proper way to design an OS.  Luckily, Mr. Torvalds was not dependent
>> on their approval, and had the confidence to move ahead.
>
>I've been trying to explain why the pattern in your example will cause
>bugs; you've been justifying it in terms of OOP metaphors. *shrug* The
>comparison is clear enough to me... :)

I find the "piece of machinery" metaphor to be helpful, but no big
deal.  Mostly, it re-inforces the idea of encapsulation, keeping the
dirty details of how an alternator works inside the component, and
presenting to the outside world, a simple interface: if you want more
current at that output, put more voltage on this input.

I'm not using metaphors to justify bad programming.  I am just having
trouble seeing how one program, side-by-side with another, is
supposedly bad.

>> >> >> I'm not sure what you mean by "side effects" here.  The show()
>> >> >> function at each level is completely independent of the show()
>> >> >> function at another level.  >
>> >> >
>> >> >But the inventory data isn't independent.  It's affected by classes
>> >> >somewhere else in the heirarchy.  Worse, it's done implicitly.
>> >>
>> >> The "inventory data" actually consists of independent pieces of data
>> >> from each class. ( numCats is a piece of inventory data from the Cat
>> >> class.)  I'm sorry I just can't follow this.
>> >>
>> >
>> >numMammals OTOH is not just a piece of data from one class - it's a
>> >piece of data stored in one class, but which stores data about events
>> >in many different classes, all of which are outside it's scope.
>>
>> Exactly as we see in objects in the real world.
>
>Objects perhaps, but not classes.  This seems to be the distinction
>which is driving this whole problem; you are regarding extending a
>class as if it were adding a member to an instance.

???

>> >That's the way it has to be, if you want to write it like that.
>> >However there is nothing to say that a given problem must use a
>> >certain class structure.  If you come up with a solution like this
>> >then it's near-guaranteed that there was something badly wrong with
>> >the way you modelled the domain.  Either the program shouldn't need to
>> >know the number of instances which ever existed of subclasses of
>> >mammal or else your class structure is wrong.
>>
>> Trust me, the need is real.  We just need to find the optimum example
>> to show how Python solves the problem.
>
>Mail me some code where you need to do this in a real system, and I'll
>show you how to refactor it. :)

Let's see if we can get the Animals_2 example right, based on the
requirements I stated above.  It will be a few months before I have my
design platform ready, and it will be far more difficult to discuss
basic ideas in the context of a big system.  I think Animals_2.py has
one of everything I will be using.

>> In my work as a software product engineer, I've learned to deal with
>> two very common criticisms.  1) The user doesn't need to do that.  2)
>> The user is an idiot for not understanding our wonderful methodology.
>> These are generally irrefutable arguments that can only be trumped by
>> a customer with a big checkbook.
>>
>> I generally don't engage in these
>> arguments, but on one occasion, I couldn't resist.  I was trying to
>> show an expert how a complicated feature could be done much more
>> easily with simpler functions we already had in our program.
>>
>> His argument was basically -- every expert in this company disagrees
>> with you, and you're an idiot for not understanding how our new
>> feature works.  I replied that I was the one who wrote the User Guide
>> on that feature.  He started to say something, but it was only a
>> fragment of a word, and it kind of fell on the table and died.  There
>> was a few seconds of silence, while he tried to figure out if he could
>> call me a liar.  I just looked right at him without blinking.
>>
>> Forget what you have learned in books.  Think of a real zoo.  Think
>> how you would write the simplest possible program to do what Animals_2
>> does -- keep track of all the different classes of animals, and
>> display the characteristics of any animal or class, including
>> characteristics that are shared by all animals in a larger grouping.
>
>What you're asking is how would I implement something simply,
>providing that I have to implement it with method X.  Give me a
>functional spec - what the system needs to do from the user point of
>view - and I'll tell you how I would do it.

See above for functional spec.

>In the case of a real zoo, I can pretty much guarantee that it would
>begin
>
>>>>import PySQLdb

Don't forget.  My basic purpose with the Animals_2 example is to teach
OOP, not the use of a particular database.

>> >And, as general rule, you should think carefully before using classes
>> >to store data; that's typically what objects are for.  I used static
>> >data in programs quite a lot before I realised that it too-often bit
>> >me later on.
>>
>> Classes *are* objects.
>
>In Python, classes are 'first class objects' - you can pass them
>around as references, alter them and so on.  That's in the same way as
>functions are 'first class objects'.  That's a different and older
>piece of terminology than the term 'object' in OOP, which unhappily
>coincides with it.
>
>Wherever I can, I'll convert the discussion over to use the term
>instance if you're more comfortable with the terminology, but in the
>canonical definition a class is not an object.  Objects get created
>from classes, and the term is equivalent to instance for practical
>purposes (though you get into occasional pieces of terminology like
>'object instance' where it's just convenient to not have to say
>'object object', and 'object variable' would get kinda confusing too.)
> Check any basic text on OOP for confirmation, say
>http://java.sun.com/docs/books/tutorial/java/concepts/

I agree the terminology is confusing, and I try to use "object" only
in the most generic sense.  "Class" and "instance", as Python uses
them are OK with me.

The question, as I understand it, is whether classes should hold just
methods, or both methods and data.  Again, the examples I have seen
show plenty of data being stored as attributes of classes.  See
Learning Python, 2nd ed. p. 317.  The general form of the class
statement according to Mark Lutz is:

class <name>(superclass, ...):   # Assign to name.
   data = value                  # Shared class data
   def method(self, ...):        # Methods
      self.member = value        # Per-instance data

Methods are more prevalent in the examples than data, but as far as I
know, there is no warning to the effect: This is possible, but not
good practice.

>> I think you mean instances.  I make a
>> distinction between class variables and instance variables, depending
>> on whether the variable is different from one instance to another.
>> Every instance has a different cat.name, but all cats share the genus
>> "feline".  In fact, they share that genus with all other members of
>> the Feline class.  That is why I moved it from Cat to Feline as soon
>> as our example was big enough to include a Feline class.
>>
>> >
>> >OK: start with the basics.  We need iterative counting data about the
>> >individual elements of the heirarchy.
>> >
>> >The first thing is that we need to factor out the print statements.
>> >Your back-end data manipulation modules should never have UI elements
>> >in them.  So, whatever form the data manipulation comes in, it should
>> >be abstract.
>>
>> You are adding requirements to what I already have.  OK if it doesn't
>> slow the introductory presentation too much.
>>
>> >Secondly, we want to keep the data stored in each class local to that
>> >class.  So, Mammal can store the number of Mammals, if that turns out
>> >to be a good solution, but not the number of it's subclasses.  OTOH we
>> >could remove the data from the classes altogether.
>>
>> Think of a real zoo.  If you ask the zookeeper how many animals he
>> has, will he tell you only the number that are animals, but are not
>> also lions or tigers or any other species?  That number would be zero.
>>
>
>In a real zoo, it would not require brain-surgery on the zookeeper to
>introduce a new type of animal. :)

Adding the Feline class to the existing hierarchy was very easy.

>Also, as I say, in a real zoo you would use a database for this task. 
>Any good database design person would balk at the idea of even storing
>the number of a particular animal as an explicit variable in the
>database.  Think about that.

Just so we can move on, I will accept your assertion that a truly
bulletproof zoo program would use a database.  We still need an
example that doesn't use a database, or anything other than Python's
basic functionality, to teach students about OOP.

>> I really do want numMammals to display the total number of all
>> mammals, whether or not they are a member of some other class in
>> addition to Mammal.
>>
>> If I were to guess at your objection to this, I would assume you are
>> worried that the different counters will get "out-of-sync", if for
>> example, someone directly changes one of these variables, rather than
>> calling the appropriate functions to make a synchronized change.
>>
>> My answer to that is to make the counter variables private.  I've
>> added a leading underscore to those names.  numMammals is now
>> _numMammals.
>>
>
>OOS due to an explicit variable alteration is pretty much the
>worst-case scenario, yes.  It would require quite an incompetent coder
>to do it, but it could still easily happen.  The more likely problem
>is the failure to call the superclass constructor - which may even be
>harder to debug, since at least in the other case you can run through
>the program in a debugger and find where the variable is being
>changed, or just grep numMammals.
>
>Your faith in private variables is touching. :)

The Python policy on private variables, which I agree with, is that we
don't need to prevent deliberate action, just make sure the user
understands a variable is private, not to be altered except by the
provided functions.

>> >Thirdly, it would probably be nice if we had the ability to implement
>> >the whole thing in multiple independant systems.  Currently the design
>> >only allows one of "whatever-we're-doing" at a time, which is almost
>> >certainly bad.
>>
>> ???
>
>Supposing I want to store data for two zoos.  If the data on the
>number of animals is stored at class-level, then I literally can't do
>that without closing down the program and opening up a different data
>set.  Munging the code to have numMammals_at_zoo_1 isn't a good
>solution either. :)

OK, now I understand.  Let's make "Multi_Zoo.py" an example later in
the chapter, not part of the introduction.

>> >After a bit of brainstorming this is what I came up with.  It's not a
>> >specific solution to your problem; instead it's a general one.  The
>> >following class may be sub-classed and an entire class-heirarchy can
>> >be placed inside it.  It will then generate automatically the code to
>> >keep a track of and count the elements of the class heirarchy,
>> >returning the data you want at a method call.
>> >
>> >This is done with a standard OO tool, the Decorator pattern, but
>> >ramped up with the awesome power of the Python class system. :)
>>
>> My non-CIS students are not familiar with the Decorator pattern.  I
>> fear that will make this example incomprehesible to them.
>>
>> >
>> >The above code is 51 lines with about 10 lines of comments.  For a
>> >project of any size, this is a heck of an investment; I believe it
>> >would take a fairly determined idiot to break the system, and *most
>> >importantly*, they would be able to trace back the cause from the
>> >effect fairly easily.
>>
>> This is an impressive bit of coding, but I can assure you, as an
>> introduction to OOP, it will blow away any non-CIS student.  It may
>> also be difficult to modify, for example, if we want to do what
>> Animals_2 does, and provide a custom display of characteristics for
>> each class.
>>
>
>Hmm, do you mean the talk method or the formatting of the inventory
>data?  Because of the rather convoluted scoping rules you have to call
>say animal_farm.<superclass name>.talk(self) to access the superclass
>from within the talk method, which is a minor annoyance I guess.
>
>To format the show method differently for each class would be a little
>more awkward, though you're not doing that at the moment.

I am intending to do exactly that.  Because the example is short, you
are tempted to say I really don't need different show functions for
each class.  I can add more unique items to each class if I must,
making it look more like a "real program", or you can accept the
requirement that the small differences in the example display are
important.

How about something like this:  We put all data and formatting unique
to each class within that class, but we don't use the trick of each
class calling its parent to generate a complete display.  The
sequencing of displays could then be done by some generic function,
calling in sequence the unique display functions from each class.

>> One possibility is to make this an Animals_3 example.  Animals_1 was a
>> simple two-class structure.  It served to introduce instance
>> variables, and some basic concepts like inheritance.  When we moved to
>> Animals_2, we pointed out the limitations of Animals_1, like not
>> having enough classes to put variables like 'genus' where they really
>> belong.
>>
>> Maybe we should go one more step, and make this a third example.  We
>> can point out the limitations of Animals_2 in the introduction to
>> Animals_3.  I can see the benefit of moving the print statements to
>> the top level.  This is needed if we ever want to make the classes in
>> Animals_2 work in some kind of framework with other classes.  The
>> show() functions in Animals_2 could be modified to return a list of
>> strings instead of printing directly to the console.
>>
>> I've posted your program as Solution 3 to the exercise at
>> http://ece.arizona.edu/~edatools/Python/Exercises/  Could you give us
>> a brief description of the advantages and disadvantages compared to
>> the original.  I'm not able to do that, because I'm having difficulty
>> restating what you have said above in terms that students will
>> understand.  I cannot, for example, explain why your solution is more
>> robust.
>>
>
>Advantages:
>    Robustness; no requirement for a programmer to keep a count of
>    instances or update the count of the super class by calling it's
>    initializer.  This minimises the chance of programmer error.
>    Avoids replication of data, eliminating OOS errors.
>
>    Maintainability; all of the code for counting is contained in a
>    single module, so modifications will not require changes to
>multiple
>    similar pieces of code throughout the class structure.
>
>    Agility; we can maintain more than one zoo in a program by
>creating
>    new instances of of the animal_farm class.  Class level data would
>    limit us to data on a single zoo system.
>
>    Generality; the Collection class can be used for any problem of
>    this type.

This is excellent.  I will add it to my web-page.

>> >Admittedly the solution is on the complicated side, though perhaps
>> >someone with more experience than me could simplify things.
>> >Unfortunately, a certain amount of complexity is just a reflection of
>> >the fact that your demands strain the OO paradigm right to it's limit.
>> > You could possibly implement the same thing in Java with a Factory
>> >pattern, and perhaps the reflection API.
>>
>> Your vast experience may be blinding you to the problems non-CIS
>> students will have with these more complex solutions.  I may be
>> pushing a paradigm to some limit, but these are real-world problems
>> that should be easily solved with a good OOP language.
>
>This isn't something I'd show a programming beginner either!  I'd
>choose a different way of demonstrating a class heirarchy, myself.

OK, I'm convinced we need a third example.  Animals_2 will remain part
of the introduction, and our next example Animals_3 will be our
bullet-proof, production-quality,
what-you-better-do-if-someone-is-paying-you, final solution.

I would still like to see some simplification of Animals_JM.py
Although clarity is not specifically on your list of requirements, I
think it does impact maintainability and programmer time.

Meanwhile, I'll try doing something with your "instances instead of
classes" suggestion.

-- Dave






More information about the Python-list mailing list