Tuesday, October 24, 2006

Conversations about types

Today, as yesterday, the issue of whether explicit/early type declarations are a Good Thing or a Bad Thing came up. Sometimes, I even saw how the discussions got a bit too personal. Besides the fact that talking about people is not going to address technical issues, the observation remains: clearly, it is a tough issue to discuss. But why? And what is it about types that causes so much grief?

I had great exchanges about this topic... and I came to the following summary that I would like to write down before going to sleep.

Overall, the issue of whether to use types or not is a matter of which values you want to emphasize. Do you care about preventing errors from occurring at run time? Do you care about cost of change?

When I work with Smalltalk, I think mostly about the problem at hand because Smalltalk has this tendency to become a mirror for my thoughts. As I put more stuff into it, I get feedback that I can apply to converge to the solution I am looking after more quickly.

As with numerical integration of differential equations, the key here is the size of each integration step. Shorter feedback cycles will lead to better overall results because they allow more fine adjustments to occur more frequently. And since finding a valuable solution to pretty much any problem more difficult than a CS homework assignment requires a Serious Amount of Thought, I think it is a good idea to make the feedback cycle lag as short as possible.

Immediately, this implies that an explicit type system is detrimental. I only have 7 plus minus 2 slots in my mind's scratch ram, and the more I need them for thinking about things other than my problem is going to cause me grief. If I need to swap out parts of my problem to think about explicit type declarations, then I am going to spend time and energy

  1. thinking about the problem of specifying explicit types, which also comes with rules and process to follow etc, and
  2. forgetting and remembering how I was thinking about my actual problem,
instead of thinking about what I should be thinking about: how am I going to express and manifest my (vague) ideas about something in a formal system of computation.

Since I only have so much time to achieve my goals, I'd rather spend time with my problems rather than with manual tools for finding simple errors. In particular, since explicit type tools are typically associated with "write-compile-run-crash-post mortem debug" programming cycles, my feedback cycles would be much more longer. This will inevitably lead to decreased solution accuracy, or at best, to increased energy expenditure to obtain an equivalent result.

Plus, of course, type systems do not let us fix problems in an execution context, thus making us imagine how things would break instead of seeing the actual bug in action. And we know how wrong we can be when we imagine things. So it seems to me that debugging in a debugger is more valuable.

Therefore, if we are to get value out of a type system, it must be of the kind that does not cause us additional work when we are writing actual code --- such as in the form of a button that we press when we so desire.

But good type inference engines are hard to come by. So instead of writing a better tool, let's cause tolerable manual work for the developers and use type annotations instead. In other words, you write your code first, then you annotate and run a type checker.

And it seems like an ok thing to do. You do not pay when you write the code, and whatever amount you pay seems reasonably bounded. Until, of course, comes change and new version 2.0 requirements. The moment you start changing the code again, all those type annotations become invalid. So now you have two options.
  1. Maintain type annotations as you change code... but that gets you into the situation where your actual development process is hindered with productivity taxes, or...
  2. Forget about the type annotations until you are about to release, then fix them all.
Since the first option seems undesirable, one would go with the second one. But then you ask... why put so much work into something that you are going to throw away? Why can't we put our intentions into a place where they do not lose value so quickly when the slightest change occurs? And why should overall cost of change be allowed to increase? Because the more time you spend type checking version 2.0, the further out version 3.0 is pushed into the future.

So, in conclusion, a type system that provides actual value to developers must
  1. be non intrusive with respect to developer work, and
  2. not need manual maintenance from developers.
I get to these conclusions because I think what developers should do is this most difficult thing of materializing a computer expression of a problem such that a process running through this expression can produce valuable answers. That is what is difficult about being a software developer, not this "secretary work" about filling type declaration forms, complying with syntax sugar, and smuggling our work through the compiler customs so we can see it crash sometime later.

Thus, given the following two options,
  • A mandatory, early declaration type system, or
  • No type system at all,
I am forced to take the no type system at all option because I think spending considerably more time trying to find an elegant solution will make it far easier to fix whatever simple errors slip through my fingers only to be almost certainly caught by functional testing.

I simply cannot waste time working on anything else than my problems. I only have one life to find elegant solutions to problems. I do not need to think about blame. I do not need to think about shame. I do not need something to tell me I didn't comply. I need something that helps me be more creative. Mandatory type systems do not help neither bring overall value to this endeavor.

Now, for the times when I really want a safety net, I'd rather write a framework that lets me express what those safety nets are. This, of course, is also covered in my book.

8 comments:

Greg Buchholz said...

And what is it about types that causes so much grief?

I think part of the problem arises when we try to be too general while talking about type systems. There seems like such a wide spectrum of type systems (think of all the differences between languges like C, C++, Java, OCaml, Haskell, and Omega), that being general implies being vague and comes with the danger of being over-general and wrong. Being more specific can only help to keep people from talking past each other. When we write about types, precision will help remind us of the limitations of our own experience, and when we read about types, it will provide crucial context regarding the authors point.

Andres said...

What I meant by that question was why talking about types causes so much friction.

In addition, though, the rest of the discussion becomes more specific with regards to type systems. In particular, if they explicitly appear in your development work, they cause grief because it's more stuff that you need to take care of.

I wondered last night about the fraction of the developer time that is spent dealing with explicit type systems as opposed to doing the work. What could it be in languages like Java?

Let's say it's 10%, for illustration purposes. Now, go to a manager and tell her/him that 10% of the development resources are going into a system that addresses *simple mistakes*. Not even the hard ones, but the *simple* ones. So, out of 10 months of work, 1 goes into fluff.

Does anybody know the actual percentage?

Isaac Gouy said...

Andres said... What I meant by that question was why talking about types causes so much friction.

Andres, the friction comes from the way people often talk about types - as we can see from your blog posting, which is not about conversation but about advocacy.

You say only good things about not using types, and you say only bad things about using types.

You talk in generalities as though you don't understand Greg's comment that there are huge differences between languages like C, C++, Java, OCaml, Haskell,... Things which might be true of Java might not be true of Haskell.

And you say some really strange things like "But good type inference engines are hard to come by" - did you try Google?

Andres, the friction comes from putting forward a very one-sided story and not being interested in hearing the other story.

Andres said...

Isaac,

I am sorry if this seems advocacy, however I think I clearly stated it is my personal opinion. If you do not agree, then that is fine --- as long as I have the right to disagree with you as well :).

Thanks,
Andres.

Isaac Gouy said...

Andres, you asked the question what is it about types that causes so much grief? but you only seem interested in your own answer to that question ;-)

Again that's "why talking about types causes so much friction" - the people talking are only interested in their own answers - they aren't interested in listening to other answers.

I am sorry if this seems advocacy, however I think I clearly stated it is my personal opinion.
Do you think it was advocacy?

Andres said...

Isaac,

You asked what caused grief, I provide you my answer, then you claim that I am only interested in my answer. ???...

You claim that I am doing advocacy, I clarify it's just my opinion, and then you ask me if I thought it was advocacy. ???...

This conversation can serve no purpose anymore.

Goodbye,
Andres.

Isaac Gouy said...

Is it possible you misunderstood what I wrote?

Anonymous said...

Truly it is very difficult to discuss this topic without sharing a perspective or point of view, which was one of the leading statements in the writer's topic. This argument is analagous to political debates placing one rather large party vs. another rather large party. Both have very good reasons, in their own minds, as to why they think or act like they think about things the way they do.

The topic goes on to lightly step through the deduction of the author's decision as to his typing preference. Along the way we were enlightened with a few of the perspectives that shaped his thinking.

To me, that all seems within reason. No bashing, just sharing of thoughts.

My point might be to ask, what good reasons are there to pre-declare a type? Does, for instance, ensuring that an integer or some other type argument make my application more robust, more stable, less likely to fail, less likely to be incorrect?

I've never asked these questions of others and so have consequently never received an answer. I have, however, been unable to answer yes to any of the parts of my second question. There must be good reasons though, or all this energy seems wasted. I'm suspect that Lisp-lovers and Scalar-supporters look at Smalltalk-friendly folks as too type dependent.

For me, software development bliss is to enjoy elegant expression, apply focus to problem solving with heavy emphasis on testing, and to remove 95% of the syntactic clutter. So, my choice, thus far, has been Smalltalk. It's just funner :)