in praise of type checking

R

Roedy Green

I changed the result of a widely used method from boolean to int. The
neat thing was the compiler (actually the Intellij syntax checker)
made sure I fixed up every invocation of that method. It would not let
me forget even one.

Imagine a language with loosey goosey type checking where it was
entirely up to you entirely to ensure all the invocations were
corrected. You could never be sure.
--
Roedy Green Canadian Mind Products
http://mindprod.com
It should not be considered an error when the user starts something
already started or stops something already stopped. This applies
to browsers, services, editors... It is inexcusable to
punish the user by requiring some elaborate sequence to atone,
e.g. open the task editor, find and kill some processes.
 
L

Lew

Roedy said:
I changed the result of a widely used [sic] method from boolean to int. The
neat thing was the compiler (actually the Intellij syntax checker)
made sure I fixed up every invocation of that method. It would not let
me forget even one.

It must not have been that widely used, then, if all the uses were in the one project.
Imagine a language with loosey goosey type checking where it was
entirely up to you entirely to ensure all the invocations were
corrected. You could never be sure.

If the method were actually widely used, then all your users would discoverthe uses that IntelliJ had no access to.

Type checking can only check the code to which you have access. If the APIin question were available to more than one project, especially if some ofthem weren't yours, it'd still be entirely up to you entirely to ensure all the invocations were corrected. You could never be sure.

Until you get the angry support call.
 
D

Daniel Pitts

Roedy said:
I changed the result of a widely used [sic] method from boolean to int. The
neat thing was the compiler (actually the Intellij syntax checker)
made sure I fixed up every invocation of that method. It would not let
me forget even one.

It must not have been that widely used, then, if all the uses were in the one project.
Imagine a language with loosey goosey type checking where it was
entirely up to you entirely to ensure all the invocations were
corrected. You could never be sure.

If the method were actually widely used, then all your users would discover the uses that IntelliJ had no access to.

Type checking can only check the code to which you have access. If the API in question were available to more than one project, especially if some of them weren't yours, it'd still be entirely up to you entirely to ensure all the invocations were corrected. You could never be sure.

Until you get the angry support call.
Unless you knew that was likely, in which case you would deprecate the
old method and create a new method which returns int.

Related to type checking, it sounds like Roedy went from "I need a
yes/no status" to a "I need more types of status."

int is the wrong way to go for that Roedy. Consider enum or a Status
class. ;-)
 
R

Robert Klemme

I changed the result of a widely used method from boolean to int. The
neat thing was the compiler (actually the Intellij syntax checker)
made sure I fixed up every invocation of that method. It would not let
me forget even one.

I'm surprised you mention the compiler and syntax checker. In my
Eclipse changing the return type of a method is a refactoring which will
easily change all affected methods in code which is part of the project.
Lew's caveats apply of course.

Kind regards

robert
 
E

Eric Sosman

I changed the result of a widely used method from boolean to int. The
neat thing was the compiler (actually the Intellij syntax checker)
made sure I fixed up every invocation of that method. It would not let
me forget even one.

Imagine a language with loosey goosey type checking where it was
entirely up to you entirely to ensure all the invocations were
corrected. [...]

Are you speaking of Python, or of Lisp?
 
R

Robert Klemme

I changed the result of a widely used method from boolean to int.  The
neat thing was the compiler (actually the Intellij syntax checker)
made sure I fixed up every invocation of that method. It would not let
me forget even  one.
Imagine a language with loosey goosey type checking where it was
entirely up to you entirely to ensure all the invocations were
corrected.  [...]

     Are you speaking of Python, or of Lisp?

.... or Ruby. These languages work remarkably well and in fact for me
it's more fun to code in Ruby than in Java.

Cheers

robert
 
A

Arved Sandstrom

I changed the result of a widely used method from boolean to int. The
neat thing was the compiler (actually the Intellij syntax checker)
made sure I fixed up every invocation of that method. It would not let
me forget even one.

Imagine a language with loosey goosey type checking where it was
entirely up to you entirely to ensure all the invocations were
corrected. You could never be sure.

I'm not sure of the technical meaning of "loosey goosey" type checking:
I expect you mean a mishmash of dynamic typing + weak typing, maybe more
so the weak typing aspect, but you'd have to explain. Or perhaps you
mean type safety, which is different yet again - dynamic typing can
absolutely be type safe, for example.

Having said that, I don't myself see the awfulness inherent in *me*
having to check that all the uses of a changed method are still correct.
For at least the first 25 years of my programming career this is what I
did anyway, on the hopefully rare occasions that I'd make such a change
well into coding. After all, there were not that many IDEs available to
do the grunt work [1].

Also, in which circumstances would you be willing to change the return
type of a method in such a significant way (boolean to int is profound)
and _not_ manually (visually and individually) check each and every call
site yourself? How can you just leave it up to the IDE to do the
refactoring, and report back simply that code will continue to compile?

AHS

1. I leave aside the argument that a comprehensive set of command-line
tools or something like Emacs *is* an IDE also.
 
R

RedGrittyBrick

I changed the result of a widely used method from boolean to int. The
neat thing was the compiler (actually the Intellij syntax checker)
made sure I fixed up every invocation of that method. It would not let
me forget even one.

Imagine a language with loosey goosey type checking where it was
entirely up to you entirely to ensure all the invocations were
corrected. You could never be sure.

The problem might not arise. Depending on which language you mean and
how you apply your knowledge of the language to the intended use of the
method.

For example, in Perl, if I changed a method so that it returned an
integer instead of a boolean I would do so in such a way that any
existing code calling that method could continue to function unchanged.
Perl can quite happily treat any integer as a boolean, I would just have
to ensure that I return an integer value that will be treated as (say)
false under circumstances where the original method would have been
expected to return false.

In general I suspect it is rare to change a method's return value so
radically. I'd be much more likely to create a new method with a new
name and have one method call the other for the bulk of it's processing.
In other words, make one method a wrapper for the other (to eliminate as
much duplication of code as is sensibly possible).

I like strict typing but I don't think your example is an especially
good justification of it. It could be used to support the opposite
contention.
 
R

RedGrittyBrick

The problem might not arise. Depending on which language you mean and
how you apply your knowledge of the language to the intended use of the
method.

For example, in Perl, if I changed a method so that it returned an
integer instead of a boolean I would do so in such a way that any
existing code calling that method could continue to function unchanged.
Perl can quite happily treat any integer as a boolean, I would just have
to ensure that I return an integer value that will be treated as (say)
false under circumstances where the original method would have been
expected to return false.

To illustrate:

Let's say I have an object "store" and I have a method "contains()" that
takes an argument and returns boolean telling us if the store contains a
matching element. I might use it thusly in a zillion places

if ($store.contains($APPLE)) {
$store.sell($APPLE);
} else {
die "Out of $APPLE!";
}

Now lets say I change contains() to return a count instead of a boolean.

My zillions of places treating the return value as boolean still work
unchanged. Hurrah for loosey goosey!
 
A

Andreas Leitgeb

Roedy Green said:
I changed the result of a widely used method from boolean to int. The
neat thing was the compiler (actually the Intellij syntax checker)
made sure I fixed up every invocation of that method. It would not let
me forget even one.

So I presume you didn't have anything like this in your code:

{
foo(yourMethodToChangeToInt());
}
void foo(int i) { ... }
void foo(boolean b) { ... }
boolean yourMethodToChangeToInt() { ... }

After the change, the other foo will be called.
The point is, that the compiler won't necessarily present
you *all* call-sites of your method, not even all those
where the result is actually used.
 
G

Gunter Herrmann

Hi!

Robert said:
... or Ruby.

And then there are languages where you can decide if the compiler should
be that picky.
There are for instance: Clipper5, Perl, Visual Objects...
The advantage is:
You can create all "regular" code in strict mode, the few places using
nasty tricks can be the exception and special TLC.

Gunter in Orlando, Fl
 
R

Roedy Green

I'm surprised you mention the compiler and syntax checker. In my
Eclipse changing the return type of a method is a refactoring which will
easily change all affected methods in code which is part of the project.
Lew's caveats apply of course.

I changed the return type. That meant the caller now had to deal with
3 possible values instead of two. There is a no way a refactor can
handle that. It is called Change Signature in IntelliJ. It is great
for swapping parms, or changing a type, or adding a new parm. When you
add a new parm, you still have to visit all the invocations to touch
up if the default value does not apply.
--
Roedy Green Canadian Mind Products
http://mindprod.com
It should not be considered an error when the user starts something
already started or stops something already stopped. This applies
to browsers, services, editors... It is inexcusable to
punish the user by requiring some elaborate sequence to atone,
e.g. open the task editor, find and kill some processes.
 
R

Roedy Green

I don't myself see the awfulness inherent in *me*
having to check that all the uses of a changed method are still correct.

It is not about having to check, it is about feeling confident the
final work is perfect. It does not rely on me being perfect. This
sort of work is very tedious. To catch an error by proofreading or by
debugging takes much much longer than having the type system check for
you. And further, no matter how much checking you do, you still are
not 100% sure it is correct.

--
Roedy Green Canadian Mind Products
http://mindprod.com
It should not be considered an error when the user starts something
already started or stops something already stopped. This applies
to browsers, services, editors... It is inexcusable to
punish the user by requiring some elaborate sequence to atone,
e.g. open the task editor, find and kill some processes.
 
R

Roedy Green

It must not have been that widely used, then, if all the uses were in the o=
ne project.

It was widely used within the project. It is internal code I use for
generating references to bookstores/books/electronics at various
online stores.

Even if it were widely distributed, and even if it were a public
method, type checking at least warns my clients I have changed the
signature of a public method without warning them. They may want to
shoot me, but at least they know precisely WHY they want to shoot me.
--
Roedy Green Canadian Mind Products
http://mindprod.com
It should not be considered an error when the user starts something
already started or stops something already stopped. This applies
to browsers, services, editors... It is inexcusable to
punish the user by requiring some elaborate sequence to atone,
e.g. open the task editor, find and kill some processes.
 
G

Gene Wirchenko

On Fri, 07 Oct 2011 12:43:19 -0700, Roedy Green

[snip]
Even if it were widely distributed, and even if it were a public
method, type checking at least warns my clients I have changed the
signature of a public method without warning them. They may want to
shoot me, but at least they know precisely WHY they want to shoot me.

Careful. Maybe they could get a justifiable homicide defence out
of that. Please ask your executor to keep us posted. <BEG>

Sincerely,

Gene Wirchenko
 
G

Gene Wirchenko

It is not about having to check, it is about feeling confident the
final work is perfect. It does not rely on me being perfect. This
sort of work is very tedious. To catch an error by proofreading or by
debugging takes much much longer than having the type system check for
you. And further, no matter how much checking you do, you still are
not 100% sure it is correct.

One never is, anyway, but why take chances?

I like what Hoare said about it: "The story of the Mariner space
rocket to Venus, lost because of the lack of compulsory declarations
in FORTRAN, was not to be published until later. I was eventually
persuaded of the need to design programming notations so as to
maximize the number of errors which cannot be made, or if made, can be
reliably detected at compile time. Perhaps this would make the text of
programs longer. Never mind! Wouldn’t you be delighted if your Fairy
Godmother offered to wave her wand over your program to remove all its
errors and only made the condition that you should write out and key
in your whole program three times! The way to shorten programs is to
use procedures, not to omit vital declarative information."

I also like: "There are two ways of constructing a software
design: One way is to make it so simple that there are obviously no
deficiencies, and the other way is to make it so complicated that
there are no obvious deficiencies. The first method is far more
difficult."

Sincerely,

Gene Wirchenko
 
E

Eric Sosman

It was widely used within the project. It is internal code I use for
generating references to bookstores/books/electronics at various
online stores.

Even if it were widely distributed, and even if it were a public
method, type checking at least warns my clients I have changed the
signature of a public method without warning them. They may want to
shoot me, but at least they know precisely WHY they want to shoot me.

Even in my private code that I never intend to distribute to
anyone at all, I make a point of changing something's name if I change
its nature. That's seldom onerous, because a change in nature usually
means the old name is no longer appropriate:

/* old */ boolean isImportant() ...
/* new */ float[] isImportant() ... // say, what?
 
R

Robert Klemme

I changed the return type. That meant the caller now had to deal with
3 possible values instead of two. There is a no way a refactor can
handle that. It is called Change Signature in IntelliJ. It is great
for swapping parms, or changing a type, or adding a new parm. When you
add a new parm, you still have to visit all the invocations to touch
up if the default value does not apply.

Oh, yes! Of course you are right. Shouldn't have posted that late.
Sorry for the noise.

I find interesting that the debate static vs. dynamic typing comes up
every once in a while. The static typers have the intuition on their
side that with more expressiveness in languages and stricter enforcement
of contracts less errors will happen. The dynamic typers usually refer
errors being caught with tests - which you have to write anyway - even
for programs in statically typed languages. And then the higher
productivity of dynamic languages may actually pay off.

Kind regards

robert
 
L

Lew

Robert said:
Oh, yes! Of course you are right. Shouldn't have posted that late.
Sorry for the noise.

I find interesting that the debate static vs. dynamic typing comes up
every once in a while. The static typers have the intuition on their
side that with more expressiveness in languages and stricter enforcement
of contracts less errors will happen. The dynamic typers usually refer
errors being caught with tests - which you have to write anyway - even
for programs in statically typed languages. And then the higher
productivity of dynamic languages may actually pay off.

Tests find bugs after they happen. The compiler finds bugs before they happen.

Tests are optional. A programmer can choose (unwisely) not to write tests;they can't choose to avoid the compiler. Tests can be incomplete; everything gets compiled. You have to write tests; you already have a compiler.

In practice, the tests "which you have to write anyway" are often not written. You've worked on projects where the tests are insufficient, yes?

As for "the higher productivity of dynamic languages", the facts have not been presented into evidence for that. The question involves fully defining"productivity", which must include maintenance costs else you have not internalized the costs that strongly-typed languages aim to avoid.

Case in point - in one Language War of PHP vs. Java for Web applications, aPHP fanboy mentioned that they allowed exception crashes, complete with stack traces, to appear in the browser when the application fubared. Well, no wonder they were more "productive". If I could bring myself to inflict crashes on the user, I'd be far more "productive", too, even in Java.

I am *not* arguing against dynamically-typed languages, nor in favor of Java. I am pointing out that any such comparison must account for the consequences and costs of each approach. Next time you have to refactor a million-plus-line software system involving dozens of programmers, think about howtype safety and other compile-time checks can or should help, or not, vs. tests and other run-time techniques. Look at the state of tests on that project, and how much they cover or fail to cover.

Unfortunately your conclusion flies in the face of published research. (I don't have references handy, sorry.) By all accounts, bugs found (and thusprevented!) at compile time are far, far cheaper than bugs found (and thusnot prevented!) in testing, which in turn are far, far cheaper than bugs found in production (surely no one can argue that those were prevented!). This is only about bugs; the cost of maintenance, enhancement and refactoring apply as well. You have to internalize all the costs to fairly compare the approaches.
 
R

Robert Klemme

Tests find bugs after they happen. The compiler finds bugs before
they happen.

Tests are optional. A programmer can choose (unwisely) not to write
tests; they can't choose to avoid the compiler. Tests can be
incomplete; everything gets compiled. You have to write tests; you
already have a compiler.

In practice, the tests "which you have to write anyway" are often not
written. You've worked on projects where the tests are insufficient,
yes?

As for "the higher productivity of dynamic languages", the facts have
not been presented into evidence for that. The question involves
fully defining "productivity", which must include maintenance costs
else you have not internalized the costs that strongly-typed
languages aim to avoid.

Case in point - in one Language War of PHP vs. Java for Web
applications, a PHP fanboy mentioned that they allowed exception
crashes, complete with stack traces, to appear in the browser when
the application fubared. Well, no wonder they were more
"productive". If I could bring myself to inflict crashes on the
user, I'd be far more "productive", too, even in Java.

I am *not* arguing against dynamically-typed languages, nor in favor
of Java. I am pointing out that any such comparison must account for
the consequences and costs of each approach. Next time you have to
refactor a million-plus-line software system involving dozens of
programmers, think about how type safety and other compile-time
checks can or should help, or not, vs. tests and other run-time
techniques. Look at the state of tests on that project, and how much
they cover or fail to cover.

Unfortunately your conclusion flies in the face of published
research. (I don't have references handy, sorry.)

Which conclusion? Here are my two points with a bit more explanation:

1. It is interesting that the discussion dynamic vs. static typing comes
up again and again. This indicates that people are not able or do not
want to settle it.

2. Static typing is not automatically superior to dynamic typing in
every case. (Neither is the opposite true but because of the thread's
subject I am of course arguing in favor of dynamic typing to balance
other positions).

To add a bit more explanation: I believe the reason for 1 is the former:
people /cannot/ settle this because "dynamic vs. static typing" leaves
out too many aspects which are important for success and cost of
software projects: these are at least nature of the software (and size),
people (skills and number) and process used. Yet people often search
for simple and catchy rules which explains the popularity of the topic.
By all accounts,
bugs found (and thus prevented!) at compile time are far, far cheaper
than bugs found (and thus not prevented!) in testing, which in turn
are far, far cheaper than bugs found in production (surely no one can
argue that those were prevented!).

Certainly. But the cost of bugs found during testing depends on the
process used: that the compiler does not catch a bug does not
automatically mean that it's late into the project that it is caught.
And "lateness" is the most driving factor for cost because the more time
passes the more code can be written which depends on the faulty code.
This is only about bugs; the cost
of maintenance, enhancement and refactoring apply as well. You have
to internalize all the costs to fairly compare the approaches.

Type information for e.g. method arguments certainly helps make code
readable but it is easy to write spaghetti code in statically and
dynamically typed languages. Maintainability also depends on quality of
documentation and the overall design.

Two more points to consider

1. Static typing won't detect design and architecture flaws which are
generally considered to be the most expensive to remedy.

2. Static typing is only of limited help in detecting concurrency issues
which are often hard to track down and thus expensive.

Kind regards

robert
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads

Ubunto 74
constructing a constant HashMap 19
Where am I? 10
naming convention 9
Java control panel anomaly 2
borrowing Constants 22
@see scope 6
code generation for the ternary operator 33

Members online

No members online now.

Forum statistics

Threads
473,772
Messages
2,569,593
Members
45,108
Latest member
AlbertEste
Top