> I've gone back and re-read the rest your questions:> - ...tell me whether my new class has all the required> methods?> without static type analysis, I don't think so :-)> - ...tell me which required methods do not exist on my> new type> again this is type based analysis.> > You seem to be asking how we can get the guarantees> provided by static type checking in a language that by> definition doesn't provide static type checking :-)

Yes, you've got it. I've been guilty in the past of saying you can't do X with Y when it was actually possible and already being done. I find that extremely embarrassing. My understanding is that these kinds of things are not feasible or at least really difficult in a dynamic language. My intent with these questions was to not assume what I already believed and try to see if there was something that I was missing. You've confirmed my understanding at least to a degree but I am still wary of making such claims.

I don't really see the logic in that. Tests can have bugs and show false positives. A test can pass after you performed a refactoring that broke your code. This will never happen with statically safe refactorings.

> Have you also proved that Eclipse's implementation is> mathematically correct?

> I'd prefer to emphasize testing over mathematically> provable (and bug-preserving) transformations. Have you> also proved that Eclipse's implementation is> mathematically correct? (Last time I used Eclipse, it had> a tendency to crash.) I'd also like to see large scale> projects built from small independent components; each> small enough to fit in one person's head.

No one has proven mathematically that public key encryption cannot be cracked with standard (non-quantum) computers. Proposing that it is necessary to prove refactoring mathematically is just rhetoric. It's pretty clear to see why static languages make it easier to refactor code safely. Most of these refactorings are proven by use, just like, say bricks, are proven to be good for building things.

> Like many others on this topic, I've come to favour> dynamic languages for many components. They keep my> software smaller, more readable, softer. Static> typing in practice seems more about strapping code to the> machine so it can run faster -- an important consideration> for some components, of course.

There are advantages to dynamic languages and I think most everyone on this thread understands that. But the key here is the 'softer' part. Sometimes softer is good (e.g. my bed). Sometimes rigidity is good (e.g. my walls). Sometimes the combination of the two works really well (e.g. my skeletal system). It depends on the context.

As an aside, here's a small example where type inference in Scala is useful beyond the normal example of saving typing when declaring a parameterized object. In Java, we'd need to declare an interface such as PersonGetter to handle this (for the type of pg). In Scala, with type inference, all we need to know is that pg has a getPerson method. So it saves a whole interface declaration.

> No one has proven mathematically that public key> encryption cannot be cracked with standard (non-quantum)> computers. Proposing that it is necessary to prove> refactoring mathematically is just rhetoric. It's pretty> clear to see why static languages make it easier to> refactor code safely.

OK, you got me there! I take your point and certainly don't think mathematical proof of an IDE's refactoring support is wanted. I just wanted to point out flaws in the original appeal to mathematical proof, but I agree that refactoring based on static analysis has to be easier with a statically typed language.

Like others here I prefer working with a dynamic language because it's easier to run code; to hop in and out of an interpreted session, to rub out and reshape.

> Most of these refactorings are> proven by use, just like, say bricks, are proven to be> good for building things.> > > Like many others on this topic, I've come to favour> > dynamic languages for many components. They keep my> > software smaller, more readable, softer. Static> > typing in practice seems more about strapping code to> the> > machine so it can run faster -- an important> consideration> > for some components, of course.> > There are advantages to dynamic languages and I think most> everyone on this thread understands that. But the key> here is the 'softer' part. Sometimes softer is good (e.g.> my bed). Sometimes rigidity is good (e.g. my walls).> Sometimes the combination of the two works really well> l (e.g. my skeletal system). It depends on the context.

But wouldn't it be nice to rearrange the walls in your house every once in a while? You can do that with software. I'd argue that 'softer' is always better.

There's been a lot of discussion here about the lack of refactoring tools for dynamically typed languages, and the amount of confidence we can have in refactoring tools for statically typed languages, but ultimately, I think that one thing that dynamically typed languages have going for them today is ease of testing.

I can't tell you how many hours of my life I've spent breaking dependencies in existing C++ and Java code just to be able to write tests. In languages like Ruby, it's very straightforward.

We can talk about the assurances refactoring tools give us when they rely on static types, but at the end of the day, we have to convince ourselves that our changes are correct, and if it's not easy to formulate our own assurances with tests, it's a real impediment.

I don't think this problem is endemic to static typing, but it is an issue with the current crop of popular languages.

> There's been a lot of discussion here about the lack of> refactoring tools for dynamically typed languages, and the> amount of confidence we can have in refactoring tools for> statically typed languages, but ultimately, I think that> one thing that dynamically typed languages have going for> them today is ease of testing.

That's an interesting statement.

It seems to me that ease of testing doesn't have much to do with the language and everything to do with the programmer. A developer who is sensitive to the importance of testing will always come up with highly testable code, regardless of the language they program in.

I think that we're seeing more testable Ruby code than testable C++ code because Ruby is more recent, and developers who use it are part of a more recent generation that has been exposed to the importance of testing.

Can you think of any features of certain dynamic languages that make them inherently more testable than, say, C++? (I can't at the moment, but I'll think about it some more)

> But wouldn't it be nice to rearrange the walls in your> house every once in a while? You can do that with> software. I'd argue that 'softer' is always better.

We are running the risk of taking this analogy too far but I'd not want load-bearing walls to be easy to move. I wouldn't want walls that contain plumbing to be easy to move. Even if any other walls could be easily rearranged, I would want these walls to still be rigid and not malleable. Again, we can take this analogy too far but I think it's applicable for now.

In the case of a load-bearing wall, my house could collapse if I try to modify it. I will need to understand how it relates to the overall structure very specifically if I do change it. There are definitely parts of a large scale system that have this kind of property and those are often best implemented with static typing. There are also many parts of a system where not much depends on them. These would be analogous to non-load-bearing walls. Dynamic languages are a good candidate for these kinds of things because the productivity they provide and because the downsides are not really pertinent in that context.

I think the main problem with the dynamic vs. static debate is that it's generally assumed that they are mutually exclusive. I use Jython a great deal and it's demonstrated to me that this is not the case at all. In the mixed paradigm approach, there is still a question of which paradigm is dominant. Is the dynamic code used to build the overall structure and uses static code or does the dynamic code get called by a static structure. There's a third option where you throw the two together in a single language which is something I don't find all that appealing. In any event, these are the kinds of things we should be discussing, not pointless arguments about what is better: soft or hard.

> I think the main problem with the dynamic vs. static> debate is that it's generally assumed that they are> mutually exclusive. I use Jython a great deal and it's> demonstrated to me that this is not the case at all. In> the mixed paradigm approach, there is still a question of> which paradigm is dominant. Is the dynamic code used to> build the overall structure and uses static code or does> the dynamic code get called by a static structure.> There's a third option where you throw the two together> r in a single language which is something I don't find all> that appealing. In any event, these are the kinds of> things we should be discussing, not pointless arguments> about what is better: soft or hard.

Is there any merit to the possibility of using Python (for example) to "sketch out" an idea and then have a converter of some kind produce the "go live" code in Scala (for example)? I heard an NPR piece recently in which an art historian said the masters used to sketch out extensively what they wanted and - only after they got it to a desired look - would they apply paint. The common belief that they just produced masterpieces on the first try is a myth.

I bring this up because I like iterative development and find it easier to develop ideas through coding them. However, I have a minimum of eight signatures to collect before one of my programs goes into production. The same signatures have to be collected for every bug fix I have to make. It would be great to have the advantage of prototyping and unit testing quickly and thoroughly while still having a compiler put the code through analysis.

> Is there any merit to the possibility of using Python (for> example) to "sketch out" an idea and then have a converter> of some kind produce the "go live" code in Scala (for> example)? I heard an NPR piece recently in which an art> historian said the masters used to sketch out extensively> what they wanted and - only after they got it to a desired> look - would they apply paint. The common belief that they> just produced masterpieces on the first try is a myth.

There's also some theories (and evidence backing them up) that at least some of the masters used camera-obscura to create paintings. But I digress...

That's a VERY interesting thought. I know of no such tool. But I imagine that such a thing could be done. I think it would be a lot easier if the syntax was shared between the two. Probably the static would be a super set of the dynamic syntax. When you 'harden' your code, the 'hardener' could insert things like method argument types (for example) and complain if it couldn't work things out. You could even get crazy and have it create interfaces or traits for you.

Does anyone know of any existing tools that do this? Is anything in development? I think this is a fairly brilliant idea, actually.

> I bring this up because I like iterative development and> find it easier to develop ideas through coding them.> However, I have a minimum of eight signatures to collect> before one of my programs goes into production. The same> signatures have to be collected for every bug fix I have> to make. It would be great to have the advantage of> prototyping and unit testing quickly and thoroughly while> still having a compiler put the code through analysis.

"Dialyzer has been applied to large code bases, for example the entire code base of AXD301 consisting of about 2,000,000 lines of Erlang code, and has identified a significant number of software defects that have gone unnoticed after years of extensive testing. It has also been used in the Erlang/OTP R10 system to eliminate numerous bugs that R9C contained in some of its standard libraries."

This would seem to be anecdotal evidence that testing doesn't replicate all the benefits of static analysis.

> That's a VERY interesting thought. I know of no such> tool. But I imagine that such a thing could be done. I> think it would be a lot easier if the syntax was shared> between the two. Probably the static would be a super set> of the dynamic syntax. When you 'harden' your code, the> 'hardener' could insert things like method argument types> (for example) and complain if it couldn't work things out.> You could even get crazy and have it create interfaces or> r traits for you.> > Does anyone know of any existing tools that do this? Is> anything in development? I think this is a fairly> brilliant idea, actually.

I think the very premise bars the existence of such a tool. If we could create a tool that can automatically generate statically typed code out of loosely typed one, we could also use that tool to implement safe refactorings automatically...

The bottom line is that the type information is *absent* from dynamically typed languages, and that humans are required to fill it in.

Still, the approach of using a dynamic language to prototype and then a statically typed one for real code makes a lot of sense, and I don't really care if I'm just going to rewrite most of the code: the hard part is figuring out the logic and how the various parts play with each other. Once prototyping has allowed you to figure that out, translating it to Java or C++ is trivial.

> I think the very premise bars the existence of such a> tool. If we could create a tool that can automatically> generate statically typed code out of loosely typed one,> we could also use that tool to implement safe refactorings> automatically...

I agree that you could not guarantee that any dynamic typed code could be converted automatically. But consider the following Python code:

def foo(): s = "string" write(s)

return s

def bar(): n = 10 write(n)

return n

def write(item): print str(item)

Now it seems to me that just by looking at this code, we can create the following Scala-esque output:

def foo(): String s = "string" write(s)

return s

def bar(): Integer n = 10 write(n)

return n

def write(item: Any): print str(item)

This is, of course, a trivial example but it seems that you should be able to get a good distance. Most code I write in Python is fairly well structured. I don't often reuse the same name for different types or things like that.

> The bottom line is that the type information is *absent*> from dynamically typed languages, and that humans are> required to fill it in.> > Still, the approach of using a dynamic language to> prototype and then a statically typed one for real code> makes a lot of sense, and I don't really care if I'm just> going to rewrite most of the code: the hard part is> figuring out the logic and how the various parts play with> each other. Once prototyping has allowed you to figure> that out, translating it to Java or C++ is trivial.

If it's trivial, why couldn't we automate this process, at least to some degree?

> That's an interesting statement.> > It seems to me that ease of testing doesn't have much to> do with the language and everything to do with the> programmer. A developer who is sensitive to the> importance of testing will always come up with highly> testable code, regardless of the language they program> in.> > I think that we're seeing more testable Ruby code than> testable C++ code because Ruby is more recent, and> developers who use it are part of a more recent generation> that has been exposed to the importance of testing.> > Can you think of any features of certain dynamic languages> that make them inherently more testable than, say, C++?> (I can't at the moment, but I'll think about it some> e more)> > -- > Cedric

I'd also be interested in any thoughts on this. I have a lot of experience with testing Java; my company has around 32,000 unit tests (= 32,000 test methods, not test classes), and as the number of tests have gotten larger it's become more and more of a maintenance issue. I've always thought that was more of an inherently difficult part of testing, though, rather than something specific to Java: it's just hard to have the discipline and foresight (especially when you're testing experience is limited at first) to structure your tests in such a way that they're tolerant of the right kind of changes and easy to modify when behavior/API changes are necessary. Preventing tests from being coupled to the wrong bits of code (i.e. code other than what's being tested) just gets hard in a large system.

My testing experience in Ruby is pretty non-existent; I've never built a large enough system in it (or any other dynamically typed language) to run into those sorts of coupling problems. But if there's some fundamental features about dynamic languages that make those problems easier to deal with, that would probably do a lot to change my opinions.