Could Python supplant Java?

Duncan Booth duncan at NOSPAMrcp.co.uk
Tue Aug 27 13:38:23 CEST 2002


joeking at merseymail.com (FISH) wrote in
news:dbc5020.0208230913.1caaf4ce at posting.google.com: 

>> There is also the cost from suddenly needing to write multiple copies
>> of the same function, or from having to use C++ templates to avoid
>> writing multiple copies of the code. Any time you have to write a C++
>> template, the cost is high.
> 
> Now this is true enough - although even if you combined all those
> different overloaded methods into one generic method, you *still*
> have to write a huge switch statement to figure out which types of
> data you got passed and what you should do with them.
> 
> void printInt(int i) { System.out.println("Your int is "+i); }
> void printString(String s) { System.out.println("Your string is "+s);
> } 
> 
> ...versus...
> 
> void print(Object o)
> {  if(o instanceof Integer)
>    {  System.out.println("Your int is "+o);
>    }
>    else if(o instanceof String)
>    {  System.out.println("Your string is "+o);
>    }
>    // Note - you need to add some more code here... it is 
>    // possible to call this method with neither of the above 
>    // types, and no error will occur.  If this was a set of 
>    // statically typed methods, it wouldn't be an issue  :-) 
> }
> 
> Which is more readable/maintainable?  And *that* was only a trivial
> example ;-)

Well, it is a personal thing, but I would go for the following as being 
more readable/maintainable than either of yours:

>>> def printIt(x):
	print "Your",type(x).__name__,"is",x
	
>>> printIt(5)
Your int is 5
>>> printIt('hello')
Your str is hello
>>> 

Oh dear, I seem to have lost that 'huge switch statement' somewhere. Oops.
:-)

Seriously though, a lot of generic fuctions will collapse down to identical 
code when you use a dynamically typed language like Python. It is probably 
even a good rule to say that if they don't collapse then you should have 
separate functions with different names to show clearly that they are doing 
different things.

>> The benefit to static typing is that I expect that when I hit the
>> 'compile and test' button, I will be told that the code failed to
>> compile, whereas without it I expect to be told that a unit test
>> failed. Sorry, I must have missed something there. Let me try that
>> again. If my unit tests are sufficiently comprehensive I get an error
>> at the same point in time as I would have got anyway. Nope, I'm not
>> sure I see a benefit. 
> 
> void wordWrap(Vector result,String breakchars,String source)
> 
> ...versus...
> 
> void wordWrap(Object result,Object breakchars,Object source)
> {  assert result instanceof Vector;
>    assert breakchars instanceof String;
>    assert source instanceof String;
> 
> First one seems more readable to me.  A matter of choice I 
> guess.  Maybe you've got shares in a keyboard manufacturing
> company?  :-)
> 
Where on earth did you get the idea that unit tests mean you put lots of 
useless asserts into your code? This is just silly.

I'll have to guess what your WordWrap function is supposed to do, but I 
suspect my equivalent would be:

def WordWrap(breakchars, source, width):
    	'''Implementation goes here'''
...
class TestWordWrap(unittest.TestCase):
  def testSimpleWrap(self):
    self.assertEquals(
      WordWrap(' ', 'The quick brown fox jumps over the lazy dog', 10),
      ['The quick', 'brown fox', 'jumps over', 'the lazy', 'dog'])

I would note the following points:

I didn't have to separately assert the type of the result, that check comes 
free when I check that the value of the result is what I expected.

I did have to think more carefully about what the function was supposed to 
do, so I added in a width parameter. Perhaps your function was going to get 
the width from some value floating around your program, but I couldn't 
tell. Perhaps your wordwrap uses proper character width vectors and 
kerning, but I can't tell that either, so I guessed the simplest form.

I haven't checked that WordWrap only accepts strings as input. I don't care 
about that: it probably accepts anything that looks sufficiently like a 
string, and since Python has two string types it would seem reasonable that 
it might accept either (but in that case I may need to add a few more 
tests).

I haven't checked that the callers of this function are passing in suitable 
parameters. That is because I'm not testing them, I'm testing WordWrap 
here, and anything that uses it will get tested elsewhere later.

The test will fail as the code stands: there is no implementation for 
WordWrap at all. This tests the test. The next step is to implement 
WordWrap, then refactor as necessary, then I might add another test, say to 
check that if I pass in a very long word I get an exception thrown.

It also occurs to me to wonder whether this WordWrap is supposed to do a 
greedy word wrapping (the way most word processors do), or a nicely 
balanced one the way TeX does. This is the sort of thing that gets 
overlooked until you come to write the tests. It may not be important to 
the customer, but perhaps it is.

> The problem with unit testing is that it is up to the humans
> to decide what needs to be tested - and the importance of each
> result.  NASA, for all its millions and millions of dollars, 
> hundreds of staff, and endless testing procedures right up 
> until two seconds before launch, still failed to note that
> a humble test for the temperature of the O-rings on their
> shuttle boosters was important.

And statically typed languages help with this precisely how?
Actually, I seem to remember that NASA knew perfectly well that temperature 
was critically important to their o-rings. Didn't they go ahead with that 
launch in spite of their own rules which should have cancelled it?

-- 
Duncan Booth                                             duncan at rcp.co.uk
int month(char *p){return(124864/((p[0]+p[1]-p[2]&0x1f)+1)%12)["\5\x8\3"
"\6\7\xb\1\x9\xa\2\0\4"];} // Who said my code was obscure?



More information about the Python-list mailing list