The Artima Developer Community
Sponsored Link

Weblogs Forum
Programming with "Duh" Typing

370 replies on 25 pages. Most recent reply: Aug 8, 2007 12:54 PM by James Watson

Welcome Guest
  Sign In

Go back to the topic listing  Back to Topic List Click to reply to this topic  Reply to this Topic Click to search messages in this forum  Search Forum Click for a threaded view of the topic  Threaded View   
Previous Topic   Next Topic
Flat View: This topic has 370 replies on 25 pages [ « | 1 2 3 4 5 6 7 8 9 ... 25  | » ]
Achilleas Margaritis

Posts: 674
Nickname: achilleas
Registered: Feb, 2005

Re: Programming with "Duh" Typing Posted: Jul 9, 2007 12:06 PM
Reply to this message Reply
Advertisement
> > Since many programming problems are intractable (that's
> > the nature of programming, see the halting problem
> etc),
> > we should test all our code. So why do we have static
> type
> > systems? they do not really prevent errors.
>
> Static typing won't "prevent" errors, but it will help you
> find some errors much faster. An example:
> http://worsethanfailure.com/Articles/Many-Shades-of-Cout.as
> px

I don't see how the C++ code "ostream& cout" could cause any problems. The following program works perfectly in visual C++ 6.0:


#include <iostream>
using namespace std;

void test(ostream &cout) {
cout << "test\n";
}

int main() {
test(cout);
getchar();
return 0;
}


>
> The compiler reported the issue and probably the lines of
> code that caused the problem on the spot. With dynamic
> typing and unit-testing it would take longer.

Well, in this particular case there would be no error, because in dynamic typing, it depends on how you use the variable. In your example, if 'cout' was used correctly inside the function, there would be no problem.

Michael Hobbs

Posts: 51
Nickname: hobb0001
Registered: Dec, 2004

Re: Programming with "Duh" Typing Posted: Jul 9, 2007 12:31 PM
Reply to this message Reply
> This is a good concrete example and I'd like to continue
> with it.
>
> Now, when you say you can change the address to be an
> Object in the dynamic language without changing the rest
> of the code, I assume you are making this new object so
> that it acts like a string object. If this is not what
> you mean please humor me and clarify a bit.

Maybe the address example isn't the best one to use to answer your question, but I'll see if I can continue with it.

So, let's say there's a "Person" class that has an "address" field, which is currently a string. There are a bunch of methods that treat it as a string, calling length(), substring(), matchRegex(), and other such string methods on it. Now, I want to change address to be an object with separate "street", "city", "state", and "zip" fields. This new object type doesn't support the string methods, nor do I want it to. (I don't want address to go on through life pretending to be a string.)

Anyway, I'm concerned that the new Person constructor will properly parse an address string into its component fields. (Yeah, I know, the Address constructor should do the parsing, but humor me.) I write a few unit tests that exercise the Person constructor's parsing routines, in order to test whether parsing is even feasible.

There are two possible changes I can make. The straightforward change is just to change the type of the address field to be an object for the sake of running these tests. The problem is, now I have to go through and change all of the methods that assume the address is a string. The other change is to add another field, parsedAddress, for the sake of running the tests. The problem is that if the tests turn out to be feasible, I have to rename "parsedAddress" to "address" and then update the parsing routines to use the new name.

Again, this is a rather contrived example, where the choice is obvious. But there are situations where it's a real PITA to change the type of an object only to discover that there's a scenario where the new type doesn't work and you have to change it all again. Granted, this can happen in both dynamic and static languages, but it seems to be much more common [for me] in the static ones.

Isaac Gouy

Posts: 527
Nickname: igouy
Registered: Jul, 2003

ceteris paribus - not! Posted: Jul 9, 2007 12:55 PM
Reply to this message Reply
James Watson wrote

> For example, I am refactoring two completely unrelated
> programs written in Java and I have been able to make
> large scale changes without breaking the code (beyond my
> own stupid errors.) I can do this because when I want to
> change something, I can either select the item in an IDE
> and have it tell me where it is used or just change it and
> let the compiler tell me what I need to change.
>
> What I find in Python is that I can barely reuse my old
> code, much less modify it without a lot of pain. I don't
> know of any tool that will allow me to select a type I
> have created and find where it is used.

imo this example clearly shows the futility of advocating static languages vs dynamic languages (or vice versa, or language A vs language B) as though all other things were equal - a great deal of effort goes into making those other things not equal!

In that example, a Smalltalk IDE would let your find all references to a class (I'm just making a point about ceteris paribus not - so let's not bother with quarrels about how much more precise tool support can be with more type-information).

Here's a documented industrial example of making large scale changes without breaking the (dynamically typed) code
http://oopsla.acm.org/extra/pracreports/TransformDataLayerReport.pdf


> I just don't think it makes sense to say Java is too
> verbose, so lets get rid of static typing.

Indeed, as the text book says: "It is a pretty obvious mistake to claim that something is necessarily true for a whole group because it happens to be true for a part of the group."


> I'm not sure that you are arguing for dynamic languages.
> I merely want to analyze more closely what is it about a
> a language that makes it more productive.

We never work with just a language - we work with a tool-chain within a particular work situation.

James Watson

Posts: 2024
Nickname: watson
Registered: Sep, 2005

Re: Programming with "Duh" Typing Posted: Jul 9, 2007 12:59 PM
Reply to this message Reply
> There are two possible changes I can make. The
> straightforward change is just to change the type of the
> address field to be an object for the sake of running
> these tests. The problem is, now I have to go through and
> change all of the methods that assume the address is a
> string. The other change is to add another field,
> parsedAddress, for the sake of running the tests. The
> problem is that if the tests turn out to be feasible, I
> have to rename "parsedAddress" to "address" and then
> update the parsing routines to use the new name.

I apologize if I am being dense here but I don't understand what this has to do with dynamic vs. static languages. Why can't you add a second field called parseAddress for testing in a static language? And once you decide that the parsedAddress works, you still have to update all the code that uses address as a String, do you not? In the scenario you describe, I'd much rather be using a static language because I know exactly what code must be changed.

Isaac Gouy

Posts: 527
Nickname: igouy
Registered: Jul, 2003

Re: Programming with "Duh" Typing Posted: Jul 9, 2007 1:20 PM
Reply to this message Reply
Michael Hobbs wrote The straightforward change is just to change the type of the address field to be an object for the sake of running these tests.

I'm confused about the example also, possibly for a different reason - to me the apparent dilemma seems to follow from a lack of encapsulation.

If we accessed the address field indirectly through a method then we can provide a different method answering an Address object for the unit tests without changing anything else... I guess I'm missing something.

James Watson

Posts: 2024
Nickname: watson
Registered: Sep, 2005

Re: ceteris paribus - not! Posted: Jul 9, 2007 1:22 PM
Reply to this message Reply
> In that example, a Smalltalk IDE would let your find all
> references to a class (I'm just making a point about
> ceteris paribus not - so let's not bother with
> quarrels about how much more precise tool support can be
> with more type-information).
>
> Here's a documented industrial example of making large
> scale changes without breaking the (dynamically typed)
> code
> http://oopsla.acm.org/extra/pracreports/TransformDataLayerR
> eport.pdf

I appreciate your providing the above document but I, unfortunately, am not familiar with SmallTalk (although I've wanted to learn it) so I think it would take a while for me to understand how this addresses my concern.

If you'll bear with me, the kind of issue I am concerned with is that I might have code that takes a method that returns a list-like object and pass my address method to it. Then that code takes that and passed it off to something else. Is there a tool that can analyze my Python and follow all calls to this method, even through these hand-offs and tell me whether my new class has all the required methods? Or if it can tell me which required methods do not exist on my new type whether I can change calls to those methods without breaking some code somewhere else? I suppose it is possible but it seems like it would be quite difficult to manage.

For this reason I'm confused when people suggest that it's always harder to change static code. My experience is that changing code in dynamic languages causes all kinds of unexpected problems. With a static language, it's very clear what needs to be addressed, even without an IDE. This allows me to decide whether the benefit of the change is going to be worth the effort up-front in most cases. With a dynamic language I feel that I might not realize how big of a task I've taken on until I'm well into the middle of it.

Isaac Gouy

Posts: 527
Nickname: igouy
Registered: Jul, 2003

an example Posted: Jul 9, 2007 1:44 PM
Reply to this message Reply
James Watson wrote "... code that takes a method that returns a list-like object and pass my address method to it. Then that code takes that and passed it off to something else."

Sorry you lost me - and rather than me guess what you mean perhaps you could make the example more concrete.

Larry Bugbee

Posts: 13
Nickname: bugbee
Registered: Dec, 2004

Re: Programming with Posted: Jul 9, 2007 1:57 PM
Reply to this message Reply
I'll make no bones about it, I'm one of those that LOVE Python for all the reasons stated. What I'd like to see, however, is the ability, if I so choose, to optionally specify a variable's type. I see several advantages.

First, it better makes the code self documenting, especially with arguments and return values. Second, there are times where you use assert statements to check types, but a type declaration is much cleaner. And finally, I'd argue there are some performance advantages if the the type be known, especially where variables are used in a function and the variable's type has already been declared and checked.

Optional typing would be the best of both worlds.

Michael Feathers

Posts: 448
Nickname: mfeathers
Registered: Jul, 2003

Re: Programming with Posted: Jul 9, 2007 2:01 PM
Reply to this message Reply
> I'll make no bones about it, I'm one of those that LOVE
> Python for all the reasons stated. What I'd like to see,
> however, is the ability, if I so choose, to optionally
> specify a variable's type. I see several advantages.
>
> First, it better makes the code self documenting,
> especially with arguments and return values. Second,
> there are times where you use assert statements to check
> types, but a type declaration is much cleaner. And
> finally, I'd argue there are some performance advantages
> if the the type be known, especially where variables are
> used in a function and the variable's type has already
> been declared and checked.
>
> Optional typing would be the best of both worlds.

I think so too. BTW, it's funny that VB has had optional typing for years, but that community never seemed to take advantage of it.

nes

Posts: 137
Nickname: nn
Registered: Jul, 2004

Re: Programming with "Duh" Typing Posted: Jul 9, 2007 2:07 PM
Reply to this message Reply
I think the extra typing is just a minor annoyance. Bill’s example highlights the real problem of most statically typed languages, close coupling.

This code

>>> v = ["Hi ", "there!"]
>>> v = v[1]
>>> v.upper()
'THERE!'


gets idiomatically translated to:

import java.util.List;
import java.util.ArrayList;
import java.util.Arrays;
 
class Example {
 
    public static void main(String args[]) {
        List<String> v = new ArrayList<String>(Arrays.asList("Hi ", "there!"));
        String s = v.get(1);
        System.out.println(s.toUpperCase());
    }
}


But to make the original code any justice it should be like this (sorry I don’t have a Java compiler at hand right now so this probably won’t compile):

import java.util.List;
import java.util.ArrayList;
import java.util.Arrays;
 
public interface UpperCaseable{
    public toUpperCase();
}
 
Class Example {
    Public static void main(String args[]){
        List<UpperCaseable> v = new ArrayList <UpperCaseable> (Array.asList(“Hi”,”there!”))’
UpperCaseable s= v.get(1)
System.out.println(s.toUpperCase());
    }
}


Who does this? Nobody. Imagine having to maintain interfaces to match how each object is being used in each section of the program in order to maintain maximal flexibility of what kind of objects you can use and you will realize that this is not very practical in Java.

This limitation of static typing is unfortunate, but can be fixed (maybe not in Java).
Another limitation of most statically typed languages is even more fundamental. I follow up on that later.

Michael Hobbs

Posts: 51
Nickname: hobb0001
Registered: Dec, 2004

Re: Programming with "Duh" Typing Posted: Jul 9, 2007 2:09 PM
Reply to this message Reply
> I apologize if I am being dense here but I don't
> understand what this has to do with dynamic vs. static
> languages. Why can't you add a second field called
> parseAddress for testing in a static language? And once
> you decide that the parsedAddress works, you still have to
> update all the code that uses address as a String, do you
> not? In the scenario you describe, I'd much rather be
> using a static language because I know exactly what code
> must be changed.

Not at all. Like I said, the example was contrived and obvious. I'll see if I can come up with something better.

Let's say that you have a collection of objects and you're not quite sure upfront how you'll need to access them, so you don't know whether you should put them in a set, a list, or a map. You arbitrarily pick a list, since it's the safest bet and is easily supported by your language.

Now, you get to writing a complex function that manipulates the objects in the collection. This is a function that will be called fairly often. On your first design of the function, you're fairly confident that you only want unique values, so you code the function so that it works with a set.

With a statically typed language, you're tempted to change the original type from list to a set so that this function has a set type to work with. In order to compile a test for the function, you need to update all other functions that access the collection to use set methods instead of list methods (which may have different names if your API was poorly designed). If you're more prudent/experienced, you would keep the original type as a list (for now) and copy the list into a set for the purposes of testing the function.

With a dynamically typed language, you simply change the type of the collection to a set and test the function. Since none of the other functions will be called during testing, you don't need to worry about them for now.

Here's the kicker. During testing, you discover that you need to access the objects via an ID value, so now you need a map instead of a set. If you were foolish enough to change the original type in a static language before, you have to change it AGAIN. Or, you learn from your experience and copy the set into a map for the purposes of testing. With a dynamic language, you just change the original type and test again.

At the end of the day, you're going to have to change all of the functions that access the collection in both a static and dynamic language, and yes, it will probably be easier to locate the access points with a static language. However, when your design is constantly morphing and you're using a static language, you're either making unnecessary updates across your entire codebase for a single unit test or you're constantly guarding yourself against these updates by making temporary copies (which you may forget to roll up into the original). Not something that is condusive to rapid prototyping.

Vincent O'Sullivan

Posts: 724
Nickname: vincent
Registered: Nov, 2002

Re: Programming with "Duh" Typing Posted: Jul 9, 2007 2:11 PM
Reply to this message Reply
> Since many programming problems are intractable (that's
> the nature of programming, see the halting problem etc),
> we should test all our code.

I'm not sure I follow the logic there. I thought the reason for testing everything is because we all find it practically impossible to write code (in any language) that does what we think it does and nothing else.

James Watson

Posts: 2024
Nickname: watson
Registered: Sep, 2005

Re: an example Posted: Jul 9, 2007 2:30 PM
Reply to this message Reply
> James Watson wrote "... code that takes a method that
> returns a list-like object and pass my address method to
> it. Then that code takes that and passed it off to
> something else."

>
> Sorry you lost me - and rather than me guess what you mean
> perhaps you could make the example more concrete.

I'm not sure if you use Python but it's generally pretty self-explanatory (which is one of the things I really like about it.) Pardon me if this code has errors as it is not a runnable snippet.

So we have our person class:

class Person:
def __init__(self, address):
self.address = address

def address():
return self.address


And then somewhere in the depths of my code I have something like this:

#...
for item in foo.handler(p.address):
#...
#...

where p is a person and foo.handler is something like this:

def handler(listprovider):
itemhandler = getitemhandler()
return bar.handler(listprovider, itemhandler)

and bar.handler list something like this:

def handler(listprovider, itemhandler):
for i in listprovider:
yield itemhandler(i)


I guess by analyzing the code, you can see that unless some changes are made, person.address must return a list, a list of items that probably must implement some subset of the String functionality but could be list functionality, depending on what itemhandler is. This isn't really a very difficult example. If you start throwing in eval calls it gets much more interesting.

I've seen refactoring tools for SmallTalk mentioned on a number of occasions. I don't know enough about SmallTalk to know whether it's similar to Python in the context of this example but I'm curious to know how it traces stuff like this if it is.

James Watson

Posts: 2024
Nickname: watson
Registered: Sep, 2005

Re: Programming with "Duh" Typing Posted: Jul 9, 2007 2:50 PM
Reply to this message Reply
> With a statically typed language, you're tempted to change
> the original type from list to a set so that this function
> has a set type to work with. In order to compile a test
> for the function, you need to update all other functions
> that access the collection to use set methods instead of
> list methods (which may have different names if your API
> was poorly designed). If you're more prudent/experienced,
> you would keep the original type as a list (for now) and
> copy the list into a set for the purposes of testing the
> function.

I guess where your example here doesn't make sense to me is that in the statically typed language, I wouldn't approach it in this way. When I change the type to a set, I'd see that I need to access the item by index right away. I wouldn't need to run a test to find that out.

What I would do would be to change the type and then follow all the little red marks that pop-up. If I found that there was code that required something that my new type could not provide, I would stop there and rethink my changes. At that point I would have made no changes and done no testing.

James Watson

Posts: 2024
Nickname: watson
Registered: Sep, 2005

Re: Programming with "Duh" Typing Posted: Jul 9, 2007 2:58 PM
Reply to this message Reply
> Who does this? Nobody. Imagine having to maintain
> interfaces to match how each object is being used in each
> section of the program in order to maintain maximal
> flexibility of what kind of objects you can use and you
> will realize that this is not very practical in Java.

It's actually not that hard and people do do these kinds of things. It's just not done that much because the syntax is ugly and verbose.

The addition of function pointers to Java would address this. I don't really see this as a big problem in static languages.

The advantage of duck-typing is that it's convenient. You can get stuff working in a short amount of time and if things aren't very clean, they can still work. But there are some downsides too and I don't think we can ignore them.

Flat View: This topic has 370 replies on 25 pages [ « | 1  2  3  4  5  6  7  8  9 | » ]
Topic: Programming with "Duh" Typing Previous Topic   Next Topic Topic: Python 3000 Plea for Help


Sponsored Links



Google
  Web Artima.com   

Copyright © 1996-2014 Artima, Inc. All Rights Reserved. - Privacy Policy - Terms of Use - Advertise with Us