The Artima Developer Community
Sponsored Link

Weblogs Forum
A Type System is a Set of Tests

73 replies on 5 pages. Most recent reply: Apr 26, 2006 7:08 AM by Achilleas Margaritis

Welcome Guest
  Sign In

Go back to the topic listing  Back to Topic List Click to reply to this topic  Reply to this Topic Click to search messages in this forum  Search Forum Click for a threaded view of the topic  Threaded View   
Previous Topic   Next Topic
Flat View: This topic has 73 replies on 5 pages [ « | 1 2 3 4 5 | » ]
Michael Feathers

Posts: 448
Nickname: mfeathers
Registered: Jul, 2003

Re: A Type System is a Set of Tests Posted: Apr 17, 2006 10:37 AM
Reply to this message Reply
Advertisement
> >We're in an odd state right now. The static vs. dynamic
> >debate is so far in the forefront that we can't seem to
> talk
> >about typing at all without the conversation moving in
> that
> >direction. It's a shame. There are so many more things to
>
> >talk about.
>
> Isn't that the truth.
>
> I definately think static typing (and other forms of
> static code checking) and automated testing are very
> similar in purpose and should be grouped together. Both
> serve to give the programmer rapid feedback as to the
> correctness of his program.

Yes!

> The problem is, often times at the early stages of writing
> a program, the programmer doesn't understand the program
> adequately for type information to be overly meaningful.
> Think of specifying type information as trying to explain
> n the details of a concept that you don't understand to
> another person. All it produces is confusion.
>
> Conversely, failing to specify type information for an
> understood program opens the door to unnecessary
> confusion. It's like being vague when there's not reason
> to be vague. It's like hiding something from the
> computer.
>
> So specifying static type information in early code is
> similar to premature optimization, but failing to do so in
> more mature code invites errors.
>
> The program should be no more and no less precisely
> defined than it is precisely understood.

This will sound like it's coming from left field, but I saw an interesting documentary a while back called 'The Mystery of Picasso.' It was shot in a weird way. Picasso painted on glass and the camera was on the other side of the glass, so you could see what he was doing as he was doing it (with a dose of time-lapse). What I was amazed at is how often he revisited things he'd just painted and just decided to paint over them, and the repaints uually started with some contour sketch, that he would elaborate further or abandon.

I like working with programmers who write a bit of code and then ask themselves "is there some simpler way of doing this?" If the answer is yes, they stop and redo it before going on. I think that filling in the types after working dynamically would be just like this, and it is just like the "Fast Green Bar" rule in TDD. The thing that is sad, is that there are so many programmers who never revisit a line of code after they have typed it. They don't sketch the contours, they start at the corner of the page and try to move outward in elaborate detail.

Isaac Gouy

Posts: 527
Nickname: igouy
Registered: Jul, 2003

Re: A Type System is a Set of Tests Posted: Apr 17, 2006 5:43 PM
Reply to this message Reply
Michael Feathers wrote
> I like working with programmers who write a bit of code
> and then ask themselves "is there some simpler way of
> doing this?" If the answer is yes, they stop and redo it
> before going on. I think that filling in the types after
> working dynamically would be just like this, and it is
> just like the "Fast Green Bar" rule in TDD. The thing
> that is sad, is that there are so many programmers who
> never revisit a line of code after they have typed it.
> They don't sketch the contours, they start at the corner
> r of the page and try to move outward in elaborate detail.

When we're working dynamically we know which things are numbers and which things are collections and ...

When we're working dynamically we have instantiated specific objects (specific types) because even when working dynamically that's what we have to do.

So what do you say is the real difference between that and working statically?


"The thing that is sad... and try to move outward in elaborate detail"
If they can make that work, repeatedly - what's the problem?

Erik Engbrecht

Posts: 210
Nickname: eengbrec
Registered: Apr, 2006

Re: A Type System is a Set of Tests Posted: Apr 17, 2006 7:03 PM
Reply to this message Reply
>> "The thing that is sad... and try to move outward in
>> elaborate detail"

> If they can make that work, repeatedly - what's the
> problem?

Dynamic typing can lead to violating encapsulation.

Huh?

Ok, so foo(Bar x) calls always calls x.doUpdate(), usually calls x.commit(), and on rare occasions calls x.rollback().

In a statically typed language, we don't need to look at the implementation, because the compiler is going to make sure we always pass foo a Bar.

But in a dynamically typed language we rely on documentation to tell us that we need to pass foo an object that has methods doUpdate(), commit(), and rollback(). Better yet, it's obvious that these methods are required if you look at the code. So look at the code.

Well someone doesn't look at the code, and the documentation doesn't exist, so he passes in an object that just has the methods doUpdate() and commit(). He also does very thorough error checking prior to entering the function, and it never occurs to him that foo() might want to roll something back.

3 months later, some bad data gets into the database that wasn't anticipated, and all of a sudden the dynamic code written by someone long-gone is throwing an exception because it wants to call rollback() and it can't.

Or better yet, foo() calls another function that calls another function that calls another function, which is "fixed" six months after deployment to call some mysterious method on Bar, but it only does so on 1/100000000 invokations. Bam! You've got an unrepeatable production error that really pisses off your users.

The point is, with static typing, these dependencies are checked. They can be checked because they've been declared. They are obvious to other programmers because they've been declared.

Types belong where types are known. Types should be known before a system is deployed. There's no reason to know them when it's first being created.

Leo Lipelis

Posts: 111
Nickname: aeoo
Registered: Apr, 2006

Re: A Type System is a Set of Tests Posted: Apr 17, 2006 7:07 PM
Reply to this message Reply
Why is there a desire to "decouple" types from the program? Like I said before: not all things should be decoupled.

Many people agree that every good thing has its degenerate case. For example, a trees can degenerate into a list. Desire for compact functions degenerates into meaningless 1 line functions. Desire for abstraction can degenerate into an inheritance hierarchy of interfaces and classes that each contain only one method, and so on. Desire to produce modular and pluggable systems degenerates into a compiler, or worse, an assembler! I mean, if you want the ultimate spreadsheet application that is super-hyper-duper-extensible, what you want is a C compiler.

Now, with this in mind, I think it's good to examine your idea. I realize that it's a cool and clever idea, and so it's not going to be easy to let go of it. :) But, try to step back and dispassionately see if it really benefits anything?

Just because something restricts something else, does it mean it's beneficial? Think about it, please. If I make it so that C compiler can only be used to compile spreadsheets, then I eliminate ALL the errors inherent in kernels, web servers, word processors and so on. Of course narrowing the expressible domain can reduce the possibility of some errors. But have you considered that purposefully ALLOWING certain errors can be a good thing if it enhances the scope of your domain?

If you "decouple" types, why not "decouple" variable names too? Why not "decouple" arithmetic operators like this:
---file.a
f1: a b c
---

---file.b
f1: + +
---

so that compiler can read file.a and file.b and understand that f1 line is addition of a, b and c? I mean, you can "decouple" anything from anything, but is that good? Surely it is good, because you can then make pluggable arithmentic expressions, right? I mean, file.b could also be:

---file.b
f1: add add
---

or
---file.b
f1: addall
---

isn't that great? ;) Just think of all this flexibility.

Like I said before, "decoupling" static types is a horrible idea. First, you can no longer see type information at a glance without a fancy GUI. Second, you cannot change type information willy nilly without breaking other things (even with so-called "pluggable" type systems), so it can't even rightly be called decoupling! If I decouple List interface from its implementation, then I can change the implementation of List without breaking any of the code that uses it. On the other hand, if a make a change to a "decoupled" static type file, I WILL break all kinds of things (unless all your variables are global in scope and you only need to change one file, but this is horrible, we're back to bad old days of globals).

It's just not right to call what you're proposing here "decoupling."

Secondly, let me make a prediction regarding these so-called "pluggable" type systems. What will happen is one of these systems will become popular and will dominate. So what's the point of adding complexity? Personally there is no way I'm going to be editing 2 files if I can edit just 1. In fact, when people compare Python to Java, the fact that you can group many Python classes in one file is considered an advantage (that I have seen). Proliferating file counts and KLOCs are bad. I think it's better to think how to reduce both KLOCs and file counts, instead of thinking how to make it so flexible that we end up back at assembly level with billions of KLOC and 10 files just to get a simple 3 class program with static typing going.

It's cool to provide hooks for pluggable type systems. But this in no way should burden or even be apparent to the developer. When someone comes up with a better type system to plug in -- it's a new language and should be treated as such. Just like c++ is a new language, even though it plugs into the same backend as c in gcc suite.

Leo Lipelis

Posts: 111
Nickname: aeoo
Registered: Apr, 2006

Re: A Type System is a Set of Tests Posted: Apr 17, 2006 7:11 PM
Reply to this message Reply
In the above post I am making two separate points:

1. It's not obvious that static typing is good just because it can restrict what can be legally expressed.

2. Types are part of the language. From the point of view of developer they should be part of the language. From the point of view of language hacker, they might be pluggable.

Leo Lipelis

Posts: 111
Nickname: aeoo
Registered: Apr, 2006

Re: A Type System is a Set of Tests Posted: Apr 17, 2006 7:26 PM
Reply to this message Reply
A few days ago I made a post about why 'foo(a, b): return a+b' is a good thing, saying that it's good for a and b to not have types. Then someone chimed in and said, "but they do have an implicit type of addable".

Now reading the post above complain about documentation, I agree: it's a documentation problem.

How about this. Instead of using static typing, is it possible to walk the source tree and determine all method calls that can reasonably be called on an object? So, if an object appears in an addition expression, then it must support addition and so on. So, instead of giving names to these functionalities like "addable", why not just let the developer see it directly as a list of methods that can be called?

Of course such a tool can be limited because a language like Python has "eval" and so on, but it will, I think, fix 99% of the issue, which is a documentation issue. If it is possible to document what should quack and what should beep that we are OK. What quacks is a duck and what beeps is a beeper, and problem solved. There is no need to give explicit names to these things.

Erik Engbrecht

Posts: 210
Nickname: eengbrec
Registered: Apr, 2006

Re: A Type System is a Set of Tests Posted: Apr 17, 2006 10:24 PM
Reply to this message Reply
> How about this. Instead of using static typing, is it
> possible to walk the source tree and determine all method
> calls that can reasonably be called on an object? So, if
> an object appears in an addition expression, then it must
> support addition and so on. So, instead of giving names
> to these functionalities like "addable", why not just let
> the developer see it directly as a list of methods that
> can be called?
>

You mean like a C++ function template? Or do you mean something that will give you understandable errors.

Or do you mean that the compiler should analyze a method/function and figure out all the methods it can possibly invoke on its parameters, and essentially do this for the entire possible call graph.

What about return types? def foo(a, b): return a + b doesn't have to return any particular type. It doesn't even need to return something that's addable, even though both of it's imputs were addable.

Anyway, back to your suggestion of letting the developer list the methods to be called.

I think it would be interesting to see a language were interfaces were implicit instead of explicit. So when you declared that a method that took a given interface as a parameter, and the compiler encountered an invocation of the method with an object that matched the interface, the compiler would automatically generate a proxy class the explicitly met the interface and delegated to the object that implicitly met it.

Gregg Wonderly

Posts: 317
Nickname: greggwon
Registered: Apr, 2003

Re: A Type System is a Set of Tests Posted: Apr 18, 2006 9:22 AM
Reply to this message Reply
The compiler always executes a very specific set of tests that validate the constructs and semantics of the syntactical elements of the language definition.

Statically typed languages include more tests in the compiler for the symantics associated with the typing that is expressed.

Dynamic languages have less semantic information and can thus make fewer assumptions about what can and will happen.

The most predominate argument about statically typed languages is most always "too much text" or "too much to type into the screen". Some people are in fact limited in their ability to use these clunky old keyboards that most of us use to enter text into computer systems.

I'd like more people to think about what arguments they would have against static typing if their own experience with typing at the keyboard, and their own physical limitations with reading limitatiosn where not present. My eyesight is narrowing and shortening as I get older. I've been getting bigger and wider screens, and now mulitple monitors are in my view.

When I'm creating a new Java application, I just randomly start typing in names of things that will be interfaces. I call methods on them, and do all kinds of off the cuff construction. Then, I start using the compiler to refine my typed text into a compilable template of the code structure that I have designed.

Now, I have a type based system, that I designed using the compiler and editor to help me get it right.

How is that different from developing a dynamic language application where you use runtime testing to accomplish the same thing?

Isaac Gouy

Posts: 527
Nickname: igouy
Registered: Jul, 2003

Re: A Type System is a Set of Tests Posted: Apr 18, 2006 11:23 AM
Reply to this message Reply
Erik Engbrecht wrote
> I think it would be interesting to see a language were
> interfaces were implicit instead of explicit.

See "Adding Dynamic Interfaces to Smalltalk"
http://www.jot.fm/issues/issue_2002_05/article1

Vesa Karvonen

Posts: 116
Nickname: vkarvone
Registered: Jun, 2004

Re: A Type System is a Set of Tests Posted: Apr 18, 2006 11:38 AM
Reply to this message Reply
> How about this. Instead of using static typing, is it
> possible to walk the source tree and determine all method
> calls that can reasonably be called on an object? So, if
> an object appears in an addition expression, then it must
> support addition and so on. So, instead of giving names
> to these functionalities like "addable", why not just let
> the developer see it directly as a list of methods that
> can be called?

Have you tried the object system of OCaml (http://caml.inria.fr/)? It works very much like you describe - except that it is actually statically typed.

Isaac Gouy

Posts: 527
Nickname: igouy
Registered: Jul, 2003

Re: A Type System is a Set of Tests Posted: Apr 18, 2006 11:56 AM
Reply to this message Reply
Erik Engbrecht wrote
-snip-
> Ok, so foo(Bar x) calls always calls x.doUpdate(), usually
> calls x.commit(), and on rare occasions calls
> x.rollback().
>
> In a statically typed language, we don't need to look at
> the implementation, because the compiler is going to make
> sure we always pass foo a Bar.

Yes we always pass foo a Bar but, without looking at the implementation, how will we know that foo(Bar x) does indeed call x.rollback() when it should?


-snip-
> He also does very thorough error checking prior to
> entering the function, and it never occurs to him that
> foo() might want to roll something back.

Are there no requirements / test cases?
Does he bother about test coverage?


-snip-
> The point is, with static typing, these dependencies are
> checked. They can be checked because they've been
> declared. They are obvious to other programmers because
> they've been declared.

All that's being checked is signature consistency (parameters, return type) - to check that the correct thing is done we need to define contracts and tests.


> Types belong where types are known. Types should
> be known before a system is deployed. There's no reason
> to know them when it's first being created.

Even in the first system, we know that's a number and that's a collection, and that's ... otherwise we literally don't know what we're doing.

Erik Engbrecht

Posts: 210
Nickname: eengbrec
Registered: Apr, 2006

Re: A Type System is a Set of Tests Posted: Apr 18, 2006 1:49 PM
Reply to this message Reply
>Yes we always pass foo a Bar but, without looking at the implementation, how will we know that foo(Bar x) does indeed call x.rollback() when it should?

You test it.

> Are there no requirements / test cases?
> Does he bother about test coverage?

Maybe, maybe not. We'd like to hope...

>All that's being checked is signature consistency (parameters, return type) - to check that the correct thing is done we need to define contracts and tests.

I debated pointing that out myself. Static typing is a relatively weak means of specifying a contract. I personally think a language should have a much richer set of constructs for specifying contracts that can be checked at compile time.

And yes, we still need tests.

>Even in the first system, we know that's a number and that's a collection, and that's ... otherwise we literally don't know what we're doing.

If you know what you're doing, than specifying types is just a little more typing, so you might as well benefit the compiler and the other programmers by putting types in your code.

Vesa Karvonen

Posts: 116
Nickname: vkarvone
Registered: Jun, 2004

Re: A Type System is a Set of Tests Posted: Apr 18, 2006 4:30 PM
Reply to this message Reply
Static typing is a relatively weak means of specifying a contract.

No it isn't. You are making a category mistake. Please distinguish between the general concept of static typing and specific static type systems. Regarding "weakness", there are static type systems that are Turing-complete.

Leo Lipelis

Posts: 111
Nickname: aeoo
Registered: Apr, 2006

Re: A Type System is a Set of Tests Posted: Apr 18, 2006 5:20 PM
Reply to this message Reply
> You mean like a C++ function template? Or do you mean
> something that will give you understandable errors.

I wasn't thinking anything fancy. Since I was thinking it was a documentation problem, the desirable artifact of such "walking the call graph" system would be a set of useful documentation.

I've seen this problem first hand where I'm using some Python module and I have no idea what it expects and the docs are poor or missing. And then it takes me a while to learn how to use the API. I think that's a real problem, but I don't think mandatory explicit static typing is necessarily a good way to solve this.

> Or do you mean that the compiler should analyze a
> method/function and figure out all the methods it can
> possibly invoke on its parameters, and essentially do this
> for the entire possible call graph.

I mean the last statement. Return types can probably be reasonable inferred. Personally I don't care about 100% solution. I think an 80% solution is good enough.

So, yes, you can have:

def foo(a,b): return 1 (literal)

or

def foo(a,b): return a+whizbang (possible typecast, need to lookup whizbang based on scoping rules, using the 80% solution mentality)

or

def foo(a,b): return lambda(...) (returns a function, so keep track of it in the call graph, or maybe don't worry about lambdas if it doesn't fit 80% mentality)


So, yes, I agree that functions can return anything. The call graph walker might be pretty complicated indeed. But, first, I only want some documentation and not compile errors, and second, I think I'd be happy with an 80% solution that works for most common cases.

The point is that when coding I roughly know how to use any API in a dynamic language, even if the author didn't bother to write any docs or didn't update them.

Statically typed languages are nice in that APIs are more or less unambiguous (unless you use the most base interface everywhere...*sigh* everything has a degenerate case, doesn't it?) even IF the author didn't bother to write the docs. That's nice. Personally I don't care about compile time type errors that much, but the docs are handy. I'm sure many think otherwise for good reasons.

Leo Lipelis

Posts: 111
Nickname: aeoo
Registered: Apr, 2006

Re: A Type System is a Set of Tests Posted: Apr 18, 2006 5:28 PM
Reply to this message Reply
> Have you tried the object system of OCaml
> (http://caml.inria.fr/)? It works very much like you
> describe - except that it is actually statically typed.

I've been putting off giving it a try, but it does sound interesting.

I am slightly concerned that OCaml is made by a team of geniuses, and while some people might think it's great, I disagree. What if, God forbid, one of them gets hit by a bus? What I mean is, just how complicated type inference is and who could maintain it? How easy is it to fix bugs in such a system and so on? If it's insanely complicated and can only be reasonably maintained by 5 people on Earth, then I'm affraid it's not a good choice for a popular language. That's also why I was saying I'd be happy with an 80% solution.

Flat View: This topic has 73 replies on 5 pages [ « | 1  2  3  4  5 | » ]
Topic: A Type System is a Set of Tests Previous Topic   Next Topic Topic: Thinking in C, Beta 3


Sponsored Links



Google
  Web Artima.com   

Copyright © 1996-2014 Artima, Inc. All Rights Reserved. - Privacy Policy - Terms of Use - Advertise with Us