Yes, though this may be due to me not having learned when to apply
this and not - I've only tested it out for fairly small projects.
Probably the core problem in how I used it was that I added checks
"all over the place". This got in the way of refactoring; in quite a
bit of code, things are passed through that are used elsewhere, and
when I added more checks for this, it was no longer trivial to change
the type of the pass-through parameter.
For instance, I was working on a firewall maintenance application, and
at some point I wanted to change from an IP address to a rule number
(or vice versa, I don't remember) as an identifier for what to
manipulate. Without checks, it was a three line change - change at
the original originator of the ID, change at the two consumers. With
type checks, I ended up needing to modify things all over the place.
The mistake, of course, was that I'd been using more concrete types
than I should at the point where I declared the checks - but - this is
a thinking shortcut that I think we all do at times. I was thinking
of that IP address as an IP address, not as an identifier for
something that could be identified another way, and it was natural to
check for what I was actually dealing with.
It is possible that conservative application of the type checking
library could be useful. I have, for instance, used it to add checks
to a hash to enforce that only Integers were inserted/indexed into it,
because I was processing data that both came from a database and from
text files, and wanted to make sure that the same kind identifier was
used (ie, that I didn't get a string "1234" from the text file and
tried to use it as an identifier, checking to find the record 1234).
Adding this check to the hash was useful - it was part of debugging
process, and meant that I could be sure that the bugs I was seeing at
least didn't come from that particular error.
Apart from that, I wonder if it might be useful to add checks at the
"edges of libraries" - the public APIs that people consume. This
would both function as very formal documentation and trap errors in
cases where they are more likely to occur.
Eivind.
···
On Jan 31, 2008 11:25 PM, Tim Connor <timocratic@gmail.com> wrote:
> See code implementing something similar athttp://people.freebsd.org/~eivind/ruby/types/
I like your warning in the readme: http://people.freebsd.org/~eivind/ruby/types/README
and I wouldn't be surprised to find that being the case. I was
considering though if a less verbose approach would be more rubyish
and less painful. None of the extra pre-declaration required in the
usual type system, but just how to make method declarations more
explicitly contractual (looking at the contractual aspect more than
the type system aspect). I suspect it is still a case of YAGNI, as I
haven't really needed it yet, too much, but there are just some odd,
harder than they should be bugs I've had to trace.
Yeah tests and BDD helps a lot, and maybe a convention of always
testing the nil and edge cases for each parameter. But when something
nested goes awry, in a situation you know exactly what the function
wants (even if it's just a responds_to), it might be nice to get a
more immediate failure. Maybe that would interfere with refactoring
and lead to a more Javaesque inflexibility, though. I dunno, to be
honest. Which is why I posted.
Apparently in your experience it just led to additional pain with
little benefit?