

Do We Create Type Systems In Dynamic Languages? - johns
http://www.codethinked.com/post/2009/04/05/Do-We-Create-Type-Systems-In-Dynamic-Languages.aspx

======
blasdel
What To Know Before Debating Type Systems:
<http://www.pphsg.org/cdsmith/types.html>

Something about type systems just inspires people to use imprecise
nomenclature and logical fallacies -- If people just referred to "Type-
Checking" when that's what they mean instead of using "Typing" to describe
everything, they wouldn't ask stupid questions like the title of this link.

Of course dynamically _type-checked_ languages have a type system -- you're
using it every time you do any operation in the language!

------
kscaldef
> We are all fully aware that if you are doing “kind_of?” checks all over the
> place then you are doing it wrong.

I think the author missed the point of what Alex Payne wrote:

> There’s lots of calls to Ruby’s kind_of? method, which asks, “Is this a kind
> of User object? Because that’s what we’re expecting. If we don’t get that,
> this is going to explode.”

They aren't checking types because they don't understand how to write
polymorphic code or something along those lines. They are checking types as
runtime assertions against programming errors; precisely the set of
programming errors that static types prevent.

I've done this myself, when I found that parts of our code dealing with
finances was mixing exact and floating point arithmetic, leading to occasional
rounding errors. I built a simple DbC system for Ruby, and added type checks
going in and out of various methods. With the contracts in place, it was easy
to track down the location of the errors, and they stay in place as
documention / protection for the future.

~~~
jeremymcanally
If you don't know what kind of object you're receiving and how it behaves,
then there's something far worse going on than a runtime check.

Even if you do those checks temporarily, I don't think they should remain
there, especially in production code.

~~~
silentbicycle
It's easy to get cocky about this if you've only worked on relatively small
projects in languages like Ruby, but being so cavalier with larger codebases
will blow up in your face. Yes, code should be well-factored, _but it isn't_ ,
so be careful.

I think type checks should absolutely remain in production code. (If you're
considering removing them for efficiency purposes, measure if it matters.) The
ambiguity that tends to creep in and cause nasty bugs isn't "is this a polygon
or a string?" (I mean, duh), but rather, stuff like, "is this measurement
currently in meters or millimeters?". Working in a dynamic language and
putting checks in the few places where it really matters is good enough, but
_it really matters_. It may help to think of type assertions as comments about
expectations and intent that are automatically checked.

Also, languages with type inference can be a good compromise. You get the
consistency checking of static typing without having to constantly remind the
compiler that it's still dealing with an int or whatever. (I like OCaml, but
it's not without its flaws. It takes a while to get the hang of working with,
rather than against, its incredibly thorough type checking.)

------
rjurney
You mean there's something wrong with writing this many times a day in Perl?

if (defined($foo) and $foo->can('bar') and $foo->bar ne '')

I really relate to the article, because I deal with Perl 5 sucking all day
long. Perl 6 has types. Moose has types. I can't use either, and so I end up
writing really lengthy code doing ad hoc type checks all over the place.

Types are important to have when you need them, and you would move to using
more and more of them on a more mature system like twitter at this point, but
I prefer that they be optional. Moose objects and Perl 6 give me that option
but don't require it, and thats nice.

Does Ruby do anything like that? Thinking about Ruby for my next project.

~~~
lsb
(If you're a startup CTO type, why are you doing Perl 5?)

Let's say you have InterestingObjects, a hash map from strings to objects. You
could say InterestingObjects['foo'].andand['bar'].andand != '', but you might
do better to rethink control flow, and reframe your problem, because there
might be an easier way than always talking about variables that might not
exist that have unknown properties. That looks like you're breaking
encapsulation.

~~~
rjurney
Perl 5 pays the bills :)

Actually, I don't have a problem with Perl 5/Catalyst
<http://www.catalystframework.org/> for a Startup, as long as you have several
people quite good at it. If you know what you're doing, the main problem is
finding good startupish Perl devs.

I confess that I don't understand your example. I'm not breaking
encapsulation, I'm just verifying that a variable is defined (avoids 'variable
not defined, can't call can' error), that it is an object with the method of
interest (avoids 'no such method' error), etc.

In other words - I am doing a type check that its a valid object of the class
I want with a non-null value on a field that should never be null. Happens all
the time. This is more easily defined once in the class in a more reasonable
object system. But Perl 5 without Moose has no such thing.

Which would seem to parallel the article. I could just assume that
$object->foo will work, but that doesn't work out too well as code grows,
because if I want my code to work or at least to easily be fixed, I have to
check sanity everywhere possible.

------
triplefox
I am an avid haXe user. It has static inferred typing with a "Dynamic" type,
"untyped" blocks, and casting, all of which work more-or-less as advertised:
the type system gets out of the way when you ask it to, and the rest of the
time you get nearly-free type-checks. Sometimes it needs a little bit of
annotation to help it along, but on the whole it's very handy for refactoring
code.

In fact, I'm sure my iteration time goes up in haXe because I see most errors
at compile-time. The ones I don't see are logic and uninitialized values.

ed: I mean time goes down, not up. Progress goes up.

------
jpedrosa
I think it's just wrong to test for the type of the variable, unless it's
really needed. Such checking detracts from what you are trying to accomplish
and from relying on the exception backtrace to give you a clue of what went
wrong when an error occurred. Also relevant is that if you are trying to pass
in a new object that should work despite not being a direct descendent of a
certain object, by checking for a certain type you restrict the usefulness of
the API. Even "mocking" a certain object can be more troublesome then.

That said, whereas many Rubyists can make more use of respond_to?(), I can
make a few uses of is_a?() every now and then. They usually make use of more
idiomatic Ruby that way than me.

On the Spec/Test side, I hope everyone is testing more functionality than
types as I am sure the type checking is just redundant in Ruby. Speaking of
redundancies, a famous motto is all you need to follow to keep it cool: "don't
repeat yourself".

~~~
Confusion
Functions only work for a very specific set of input types. On all other
inputs, something goes wrong, but that 'something' can take quite a bit of
investigating to figure out. Therefore, an assertion that verifies that the
input is indeed part of that specific set of input types is valuable: it
catches the problem at the earliest possible moment and it pinpoints the exact
problem.

~~~
jpedrosa
For every other type of error, hah, rely on what I said then?

------
tetha
I think typesystems span far deeper than most object oriented typesystems go.
In fact, I think, it goes even deeper than what haskell does (and I consider
Haskells typesystem to be among the most advanced typesystems we have today).

One question for the typesystem is: If I have this object, will it understand
message X?

Another question is: If I send this sequence of messages to this object, will
the sequence of messages exiting the object be as expected? (Or, much rather:
will a certain "interesting" subset of the messages sent by the object
(triggered by my messages) be a certain sequence? (In fact, sequence is too
restraining. I rather need to know if the messages sent by the object will
fulfill a certain predicate)

Another question is: If I conceptually send this message to that object, how
do I find the implementation of the handler of this message?

(I am sure that there are more complicated questions around and I just do not
know them).

Given these questions, consider what most static type systems do. They answer
questions 1). (Dispatch strategies and strong typing answer question 3) )
Guess what unit tests do? They answer question 2). However, in a dynamically
typed language like Python, sending a message to an object that is unable to
understand this message (read: there is no implementing method), then an
unexpected message will be sent by the object (read: an Exception is thrown).
This violates the contract. In other words: checking the contract can answer
at least question 1) already!

Thus, I think -- or rather hope -- for major improvements at typesystems,
because it appears that things are far, far more complicated than just
compile-time vs run-time and strong vs weak. Consider Eiffel. Eiffel does
contract checking. Now think about attaching contracts to objects at runtime.
This could reduce the amount of of_kind?-checks in the article. Consider
roles. Consider things like pythons metaclasses. I really think a lot of
problems come from a lack of unterstanding object oriented typing more than we
already do. (Maybe this kind of pushed me into a good direction for a master
thesis. who knows?)

------
leadnose
The more I have thought about fully dynamic languages that don't allow any
form of static typing information, the more I have begun to think that they
are not very useful. Sure, polymorphism is nice, overloading is nice, but all
of the programs I have written, have relied on some sort of typing discipline,
be it dynamic, static or whatever. I can't imagine writing a useful function
for which I wouldn't know what it's type is. Just because Java, C++ etc.
implement static typing poorly, doesn't mean static typing has to suck when
there are many languages that have inferred static typing, which in my opinion
can provide best of both worlds.

EDIT: By "best of both worlds" I mean "concise code and the benefits of the
program being well typed"

~~~
huherto
What do you mean Java and C++ implement static typing poorly? C++ has some
trade offs in order to be compatible with C. The Java static typing seems
pretty good to me.

~~~
leadnose
Maybe I should have said "they don't have type inference".

------
russell
Not if you are doing it right. The article context is unit testing a dynamic
languages vs a static language, saying that you have to do more testing with a
static language. If you do thorough unit testing, the difference isn't all
that great. The article implied that unit testing doesn't need to be as
thorough with a staticly typed language, That is just plain wrong. You may
need to do some additional testing with a dynamic language, but overall you
come out way ahead. Python instead of Java, you come out way ahead. Python
framework vs a full Java framework, the difference may be 5x or 10x.

~~~
scott_s
The Python versus Java comparison is a red herring, I think. While Java is
more verbose than Python, and some of that verbosity is from its type system,
not all of it is.

A better comparison would probably be Python versus Scala, or Python versus
OCaml.

~~~
russell
True, but I speak of which I know. If someone has such a comparison, I would
love to see it. The real measure is tokens not LOC.

~~~
ankhmoop
Then your knowledge may be too constrained to derive sufficiently
representative generalizations.

I can highly recommend:

[http://www.xoltar.org/old_site/misc/static_typing_eckel.html...](http://www.xoltar.org/old_site/misc/static_typing_eckel.html?repost)

The article (from 2003!) is an excellent treatise on the value of a proper
type system as compared to Python, and moreover, how Java's type system (or
C++, ...) should simply not be equated with "static typing".

------
martincmartin
Groovy allows you to specify types of method parameters, return values, fields
and local variables. This was needed for Java integration, but has the benefit
that you get runtime checks for types. So in Ruby you might do:

def foo(mystring): assert mystring type_of? String mystring.length end

In Groovy you could just do:

def foo(String mystring) { mystring.length }

------
jauco
Maybe. I tend to put it the other way around. Why would you need static typing
if you're going to write unittests anyway.

~~~
ankhmoop
A well-designed type system reduces the number of tests needed by allowing the
programmer to enforce correctness through the type system itself.

