views:

78

answers:

6

This answer hit a nerve with me on something I have never understood with how you handle parameter types in dynamic languages vs. a static language (my perspective being informed or deformed - as you prefer) from Java.

Given a method foo that takes a parameter bar in a dynamic language, there is no enforcement at compile time of the type of bar. The answer linked above (and the answer I have generally seen to this) is that you need to unit test properly in a dynamic language.

But at some point something outside the unit will call that method. Say this is a heavy weight object that will be mocked in any unit tests of classes that use it. Now you have many classes which call this method, and you need to change the type. To keep it simple, it used to take a number, but now requires an alpha numeric, and you need to use a method specifically available on string and not on a number object with the new requirement.

How do you change it and know the calling code will be fixed? Sure if you just change it, your unit tests will fail, but since you need to change it on purpose, you would ostensibly fix your unit tests. How do you know to fix the calling code? I don't just mean how conceptually do you know, I mean how do you know you have found all the callers and can really say it is changed.

It would seem that only very comprehensive integration tests would give you that assurance. Am I missing something?

A: 

I need 15 characters to post, but the answer is four characters long: grep.

John Lockwood
+1  A: 

This seems to be more of a refactoring question than a unit test question.

Parameters are effectively unit tested by insuring all properties and methods that are needed in a particular function are present and return the expected result. It is the interface that matters not the type.

Jason Christa
+1  A: 

The short answer is just 'more unit tests all the way up'.

the only thing that matters is that the new type also has the methods required. So if ClassA has Method1() which takes a param obj and invokes obj#M1() and obj#M2() - the only constraint on obj is that it responds to these messages. If you change the implementation to invoke a method Foo() which did not exist previously`, the tests exercising Class A fail.

Next if ClassB calls A#Method1() as part of its functionality, its tests will fail if Class B is passing an obj, which does have the required methods. If the required behavior of B isn't achieved, its tests should fail and that should direct towards changes needed in B.

Gishu
Thanks, but that is why I explicity gave the case of a heavy object - say one that does database access, that you would have to mock to have a reasonable unit test.
Yishai
ok.. so you're questions since we dont have strongly typed interfaces in dynamic languages, how do we ensure that the real object supports the same set of messages ? I'd say have some acceptance tests which use the real collaborator - not in your test suite that is executed every sec.. but one that is executed on a daily basis.
Gishu
+2  A: 

I think you've give an excellent concrete example of one of the advantages of static typing. Dynamic typing requires you to find all those call locations yourself. This is actually not very difficult though - its just a text search in your code. That's the trade-off: comfort that the compiler can cross-reference your code and make sure everything matches, vs not having distracting type tags throughout your code.

Timothy Pratley
I guess this is the answer. I would just say that the type tags can be more of a burden that just distracting. I have spent a good amount of time "fixing" code strictly to satisfy the type system, not to mention duplicating code because of it.
Yishai
Don't judge static typing by Java. Its type system is powerful enough to annoy you but not powerful enough to help you out much. You should at least check out OCaml.
Chuck
+1  A: 
  1. Code defensively. Make the change backwards compatible in the new method. Dispatch on the type of the argument; CLOS makes this easy.

  2. Use a "who calls" function of your editor or IDE.

Doug Currie
+1  A: 

Dynamic language developers need to replicate the advantages of static typing, that is, by having that tools can automatically find those errors. For the most part, this involves type inference tools. The inference itself is pretty difficult (I'm writing my PhD on doing it for PHP) but using the tools isn't terribly difficult.

There are error finding tools for:

For PHP, phc could do this with a very small amount of work.

Overall, when you don't have static typing, you need a tool to get the benefits.

Paul Biggar