Static typing ain't so bad, after all

On 8/22/06, Just Another Victim of the Ambient M. <
[email protected]> wrote:

The problem is that dynamic typing, while very powerful, also hid the

lucky if the code works…
Has anyone noticed this? How do you deal with this issue?
Thank you…

I do not agree with all you said, but I think you made a valid point.
I am completely surprised and sad how you get shouted at and insulted,
by
some of the most respectable members of the community.
I think it would have been a good approach to give OP a break and take
one
before all jumping at him at the same time.
Of course static typing has it’s merits, of course we do not want it, of
course dynamic typing has its merits, maybe you do not want it, I do, he
does.

That was a brave thread you have fought OP;) well but you were
outnumbered
:slight_smile:

Cheers
Robert


Deux choses sont infinies : l’univers et la bêtise humaine ; en ce qui
concerne l’univers, je n’en ai pas acquis la certitude absolue.

  • Albert Einstein

On 8/22/06, Just Another Victim of the Ambient M. <
[email protected]> wrote: The problem is that dynamic typing,
while
very powerful, also hid the

intent of the method. Obviously, any object that satisfied whatever the
method was trying to do will suffice as a parameter, and that would be the
point of duck typing, there was obviously some concrete example of some
type the method was expecting. It would really have helped to let me know
what that was…

Thinking about this thread, I was wondering why I’ve generally had so
little
of this kind of problem. For about a year after I first learned Ruby, I
thought the most irritating thing about the language was that I had to
do my
own type checks of all the arguments in every single method I wrote,
because
the d**n language wouldn’t do it for me. (Can you tell I’m a hard-core
security-oriented C programmer?)

When duck typing finally sunk through my thick skull, it changed
everything.
But I notice one thing. It’s often said that the intent (including the
desired datatypes) isn’t too hard to discern from a quick look at a
method’s
code or documentation. But this is primarily true if the argument types
are
simple or primitive. Strings, IOs, numbers, or collections of same. If
you’re passing around objects that are more complex, especially ones
that
incorporate domain-specific information, that’s when you really get into
trouble.

Because whether you use static or dynamic typing, you are tightly
coupling
one set of domain knowledge
(in the argument) with another (that of the method you’re writing). This
is
where a lot of fragility comes from, to say nothing of difficulty in
understanding the intent. Seeing the argument-type declarations in the
text
of a method you are trying to understand
isn’t much better than seeing them described in a document, because
your
real challenge is still to grasp how the non-primitive design contained
in
the argument interacts with that of the method.

This is where one of Ruby’s more distinctive features, the yield, can
help a
lot. I find that when I’m tempted to pass a big chunky object to a
method of
some other big chunky object, I either look for the design commonalities
that I obviously missed in the first place, or else I look for ways for
the
method to yield to the argument. Just to avoid coupling them more than
is
really necessary.

In the more typical case where you’re passing around integers, strings,
and
IOs, it just doesn’t seem to matter nearly so much. Your first guess on
looking at a method you’re trying to understand is probably going to be
right, and spelling out the arg types in the text subtracts readability
without adding comprehensibility.

In short, it’s been said here that documentation is the key to the
problem,
but I’d like to put in a good word for design as well.

James B. wrote:

(Offhand, I don’t see how static or explicit typing would help track
these sorts of issues. Unit tests might.)

Hrm. Mechanize or htmltools optionally passing HTML input through tidy
perhaps? I’ve no idea what the scope of htmltools markup error recovery
capabilities is, that just might help.

David V.

David V. wrote:

James B. wrote:

(Offhand, I don’t see how static or explicit typing would help track
these sorts of issues. Unit tests might.)

Hrm. Mechanize or htmltools optionally passing HTML input through tidy
perhaps? I’ve no idea what the scope of htmltools markup error recovery
capabilities is, that just might help.
Minimal, in my experience. There are some very, very broken pages out
there.

My current method for doing this sort of thing involves sniffing the
character set, normalising to utf-8, chucking the output through tidy to
get xml, ripping off the xml processing instruction and passing what’s
left through REXML. You have to take the processing instruction off
because if the page actually includes text in more than one character
set (you’d be surprised how often this happens), the normalising won’t
be complete and tidy will get it wrong half the time, which barfs REXML.
I can show code if you want.

In any case, this is tangential - the fundamental issue is that static
and explicit typing can’t catch semantic errors. The original paper on
Hungarian notation (which Joel Spolsky goes on about at
Making Wrong Code Look Wrong – Joel on Software) nails this problem,
but I’ve never seen a language whose interpreter/compiler enforces
matched variable and function naming conventions.

“David V.” [email protected] wrote in message
news:[email protected]

Sure, you can reuse a variable for very different purposes but is that
really such an advantage?

You don’t do this. Heck, you shouldn’t even reuse a variable for the same
purpose. Reusing variables tends to imply that you don’t really know what
their purpose was in the first place.

I don't think we disagree here.  This is one thing that dynamic 

typing
allows you to do and I’m questioning whether this is a benefit and
you’re
saying it absolutely isn’t. So, we can agree that this does not
contribute
to the benefits of dynamic typing…

The advantage of dynamic typing comes in working with the hairier design
patterns. It’s a reduction ad extremum of a way of constraining object
behaviour - the typical members of the “expliticly” typed language group
use type / class hierarchies for this, and check against those.

By "it's a reduction ad extremum of a way of constraining object

behaviour" do you mean that it reduces object behaviour in an extremely
non-constraining way?
With statically typed languages, the behaviour of an object is
defined
by membership. If this variable is a member of this set, then it may
have
these properties. So, when a function requires that a parameter be of a
certain type, it must be a member of this certain set. The use of other
types that may also work in this function but are not in this set are
(arbitrarily) excluded.
With dynamically typed langauges, because variables (including
parameters) may be of any type, parameters passed into a method will
work
as long as they, literally, satisfy the requirements of the method.
This
is much more flexable than defining arbitrary membership. It’s “ad
extremum” in the direction of flexability. Unfortunately, it’s also
flexable enough to allow you to pass a totally inappropriate parameter
into
a method but that’s the trade off. Is it worth it? Most of us think
so…

In my opinion, this amounts to promoting the use of code in 

differing
contexts (or, simply, code reuse), which is the advantage that I had
stated
before…

For (a very contrived) example any object that just so happens to
properly respond to the messages for arithmethical operations can be
substituted for an “integer” you only ever do arithmetics with without
the language runtime batting an eyelash.

This isn't a contrived example, it's just a vague one.
If you want an example you can use in the future, how about a 

function
or method that takes a vector and a list of vectors and sees if the
given
vector can be expressed as a linear combination of the list of vectors.
Because so many things have vector properties (real numbers, complex
numbers, Cartesian vectors, matrices, real valued functions, almost
anything, it seems), you can reuse this function or method with any of
these types! How amazing is that?

Vector module with documented methods that you expect from an
object “with vector properties” and some helper methods you’d use
would probably be my first move after making a vector manipulation
library with the dynamism you describe.

Just in case anyone following this thread missed it I just posted in
another thread a quite lengthy discussion of these issues called Duck
Typed Concepts for Ruby with analysis applied to collection types
(the post was prompted by the ordered hash discussion).

Matthew

On 8/22/06, David V. [email protected] wrote:

faster to type, and the fact the compiler rarely bitches at all is very,
very appealing to people that know what they’re doing most of the time.

That was a perceptive comment. The fact that there are so few true cases
of
objects that metamorphose in flight also accounts for the observed
“magical”
behavior that “duck-typing” seems to “just work” almost all of the time.
(By
magical, I mean unexpected for people like me with too many years of
experience programming in statically-typed languages.) The intention of
a
well thought-out code path is generally easy to express without typing
all
the types along the way. It doesn’t break often, and when it does break,
it
doesn’t make a big mess.

Just Another Victim of the Ambient M. wrote:

By "it's a reduction ad extremum of a way of constraining object 

behaviour" do you mean that it reduces object behaviour in an extremely
non-constraining way?

Yes. In the object-message interpretation of OO, it means an object only
needs to respond to the messages absolutely required in a context to be
qualified to be of the valid type.

extremum" in the direction of flexability. Unfortunately, it’s also
flexable enough to allow you to pass a totally inappropriate parameter into
a method but that’s the trade off. Is it worth it? Most of us think so…

*flexibility

As Chad P. pointed out, you leverage the benefits of dynamic typing
in the special / edge cases rather than the common case. If you poked
around Ruby libraries, you’d find out at least several, if not many
cases when the libraries perform strong type checks on objects passed
into them.

And for what it’s worth, I personally don’t see a problem with this. It
makes the libraries easier to document, easier to understand, and behave
more predictably. Ruby -allows- you to use (and abuse) dynamic typing,
noone’s saying you need to code to allow for it. I would personally
advocate the opposite, write predictable code most of the time, and then
do parts of it that could benefit from the dynamism by design - since
they will be inherently more error-prone, they require a lot more effort
to be written in a robust maintainable way.

If you want an example you can use in the future, how about a function 

or method that takes a vector and a list of vectors and sees if the given
vector can be expressed as a linear combination of the list of vectors.
Because so many things have vector properties (real numbers, complex
numbers, Cartesian vectors, matrices, real valued functions, almost
anything, it seems), you can reuse this function or method with any of
these types! How amazing is that?

Interesting example there. Of course, I’d personally formalise the
vector properties somehow, at least in documentation. You want these
vector properties to manifest themselves in the different types of
objects in a consistent way, and this is a constraint on the parameters
of the function already. And in good-quality code, you want to check on
whether the constraint is satisfied and fail early if it doesn’t.

Even dynamic / duck typing isn’t completely eschewing type checks, even
if you can get away with that for spectacularly long. And the problem is
that expressing the parameter constraint with “is a Vector” is a little
clearer than “has vector properties”. It’s not -that- apparent in this
example, but for more complex ones, where you need a larger set of
behaviours from the function parameters, the formal granular constraints
on them would be very verbose and hard to understand. Having “ubmrella”
concepts that are readily understood is very helpful in that case. And
the path between concept and code is sometimes a very short one - having
a mixin Vector module with documented methods that you expect from an
object “with vector properties” and some helper methods you’d use would
probably be my first move after making a vector manipulation library
with the dynamism you describe.

David V.

On Wed, Aug 23, 2006 at 08:40:17AM +0900, Francis C. wrote:

just don’t occur in daily coding. But dynamic languages sure a heck
doesn’t make a big mess.
I think much of the reason for difficulty enumerating common-case
benefits derived from dynamic typing is the simple fact that dynamic
typing makes other language features possible, or at least (easily)
usable, that would otherwise be prohibitively difficult to implement.
In other words, duck typing works silently behind the scenes most of the
time, providing the foundation for other, more direct benefits, but
doesn’t jump up in your face taking credit for stuff.