
The comeback of static typing - karterk
http://kishorelive.com/2013/02/24/the-comeback-of-static-typing/
======
tikhonj
The lack of popularity for static typing can be laid mostly at the feet of
Java and C++. A language with a truly good type system like Haskell, OCaml or
Scala gives you more advantages without many of the disadvantages of a Java-
style system.

Too bad too many people were too poisoned by Java et al to consider switching
to one of the good statically typed languages; happily, their recent
popularity (like this blog post :)) has gotten people to consider them.

~~~
narrator
You can't really say that Java and C++ are not popular languages. C++ is only
really popular, IMHO, because there hasn't ever been a good competitor to it
in the compile to native programming domain except for C. However, Go and
Rust, IMHO, are interesting approaches and I wouldn't be surprised if Go or
Rust replaced C++ over the next 10 years. I imagine C will still maintain its
popularity in very low-level systems programming.

The thing about Java is that it is really hard to write clever hard to
maintain code in it. Sure, it makes it painful to develop with, but because it
leads to maintainable code the code never gets thrown out and rewritten and
almost by accident very large multi-million line code bases grow over time in
it. These huge code bases lead to a lot of jobs for people doing maintenance
on them, not because developers like the language, but because the code still
works and never becomes impenetrable, as most large code bases often do.

~~~
fauigerzigerk
I like Go, but it will never replace C++. Nothing that uses a garbage
collector ever will.

The Go authors are saying that Go is for "systems programming". What they
apparently mean by that is server side infrastructure stuff, the kind that is
now frequently written in Java. Things like Hadoop, Tomcat or even database
systems.

What they don't mean (I believe) is operating systems, device drivers,
embedded systems, real time stuff including many trading and telecoms systems,
graphics pipelines, signal processing, libraries that are too complex to
rewrite in every language (like browser engines), etc. There's a very long
tail of these things and it's growing as we get more intelligent connected
devices.

Much of that is now written in C++. The question is, will C come back to
replace C++? I don't think that's going to happen. I love C. It was my first
language and I admire its simplicity. But there is one thing that C++ has over
C: RAII. RAII is an ingenious universal resource management tool that gives us
90% of the productivity gains we get from garbage collection without any of
the unpredictability, and it helps with resources other than memory as well.

Forget templates and all that fancy stuff. C++s raison d'etre is RAII. So, I
think, Rust may have a chance to replace C++ (purely from a technological
perspective) but Go unfortunately does not.

~~~
pjmlp
> I like Go, but it will never replace C++. Nothing that uses a garbage
> collector ever

Only future will tell.

I have used in the past desktop operating systems (Native Oberon and AOS)
without any single line of C++ code, written in GC aware system programming
languages (Native Oberon and Active Oberon).

I do like C++ a lot, but I am quite confident that manual memory management
will eventually be a sweet memory of old coders.

~~~
pjmlp
Update to my own comment.

I don't mean that Go will be that language per se, but that whatever we might
use for doing systems programming in future OSs will be GC enabled, even if it
allows for some way to do unsafe/system _local memory management_.

------
Chris_Newton
As no-one else has mentioned it yet, here’s a link to a copy of Chris Smith’s
excellent “What to know before debating type systems” article:

[http://blogs.perl.org/users/ovid/2010/08/what-to-know-
before...](http://blogs.perl.org/users/ovid/2010/08/what-to-know-before-
debating-type-systems.html)

If you’re at all interested in the real strengths and weaknesses of different
kinds of type system but don’t yet have much experience in the field, this is
a solid and impressively neutral starting point.

------
stephen
I think language evolution will always be cyclical like this--dynamic
languages sprint ahead, and the static languages eventually catch up.

The reason is that dynamic languages are so easy to build--they usually start
out as hobbyist projects. Not to overly-trivial it, but these days most anyone
can sit down with a compiler book and have an interpreted language up and
going quickly.

So dynamic languages evolve quickly--it's easy to try new things, see if they
work, see if they don't.

Static languages, on the other hand, are hard to build--you don't often see
hobbyist language developers coming up with type systems in their spare time.
Type systems are hard.

And the tooling for static languages is hard too--dynamic language users live
in emacs/vim/Sublime, but static language users are going to want an Eclipse
IDE, refactoring, etc., etc.

So, static languages evolve slower.

 _But_ once someone has put the time and effort into a static language, and
has the tool chain polished, I assert that most programmers (of course not
all) that sprinted ahead to the dynamic languages will find themselves tempted
to wander back.

If the syntax is the same (once the static languages catch up), why wouldn't
you want static typing, given that, even in dynamic language programs, 95%+ of
the calls could be statically verified anyway?

(Admittedly, how you deal with the remaining 5% (reflection, macros, XML,
whatever) is left an exercise to the reader.)

Great case in point: Groovy. The original creator, James Strachan, was a
hobbyist, and I believe (admittedly putting words in his mouth), if not
consciously, built Groovy as a dynamic language because it was easy. But now
he prefers Scala, which is basically the same syntax, but with all of the
extra infrastructure around typing/tooling/etc.

~~~
vorg
> But now [James Strachan] prefers Scala, which is basically the same syntax,
> but with all of the extra infrastructure around typing/tooling/etc.

James has actually moved on from Scala to helping build statically-compiled
language Kotlin!

~~~
stephen
Ha! How interesting. I didn't know that; thanks for the update.

------
adrianmsmith
_"Over time, not only have I learned to appreciate languages with good type
systems, I actually now prefer them for solving certain classes of problems."_

I think that dynamic typing seems easier at first, but after a while you see
how static typing would catch mistakes you make. While one programmer gains
the experience necessary to appreciate static typing, a new programmer starts
programming and doesn't have that experience yet, thus the static vs dynamic
debate is always with us.

I described it here: [http://www.databasesandlife.com/the-cycle-of-
programming-lan...](http://www.databasesandlife.com/the-cycle-of-programming-
languages/)

~~~
andyidsinga
thats very true it will always be with us. i started in C ..spent a lot of
time there and felt crazily liberated in perl, php and javascript. - but i
still love and use C, ( and recently objective-c ).

this all boils down to skill with tools - cordless drills are amazing ..and so
are floor drill presses

------
cletus
I think static typing (10+ years ago) got a bad rap not because of static
typing as such, but everything that came with it (and didn't necessarily need
to). I'm talking about the languages of the time (C, C++, Java primarily).

C is a bit of the one out here in that its static typing is a really thin
veneer as you can cast things to whatever you want them to.

Python and Ruby (in particular these two) more than anything else allowed you
to write really terse, expressive code. The canonical Python example of this
is defining a tree data structure:

    
    
        def tree(): return defaultdict(tree)
    

or solving the N-queens problem in ~6 lines of code [1].

Java and C++ OTOH were (and are) _much_ more verbose but only some of this has
anything to do with static typing.

All of this is one reason I'm incredibly bullish on the future of Go for such
reasons as:

\- no interfaces. If an object implements the methods expected by a consumer
then it compiles otherwise it doesn't;

\- incredibly simple OO system;

\- no exceptions as such (particularly checked exceptions in the case of Java,
which IMHO are just horrible). Some consider this a minus. I tend to think
that exceptions tend to get abused for flow control and aren't the panacea
they're made out to be;

\- simple semantics for function returns and the ability to return multiple
items;

\- opinionated formatting (I'm not one of those people who has almost
religious zeal for the placement of curly braces and indenting so I'd rather
just have a standard and stick to it, whatever it is);

\- compiles to a binary rather than running on a VM;

\- simple grammar with fast compilation. This last point is contrasted
particularly well with C++;

\- coroutines (or rather goroutines) as a first-class language citizen for
solving concurrency problems;

\- the "defer" mechanism for resource cleanup. I find this _much_ easier to
read than tortured try-finally semantics and nesting.

Another way to put it is this: a lot of vim/emacs users judge IDEs as horrible
based on having (often briefly) used Eclipse, which is a bit like judging the
car by having once driven a 1975 Trabant.

Don't judge static typing by Java or even C++. Judge it by Go.

[1]: <http://rosettacode.org/wiki/N-queens_problem#Python>

[2]:
[http://www.time.com/time/specials/2007/article/0,28804,16585...](http://www.time.com/time/specials/2007/article/0,28804,1658545_1658533_1658030,00.html)

~~~
gnosis
_"Python and Ruby (in particular these two) more than anything else allowed
you to write really terse, expressive code."_

If you like being able to write terse, expressive code, you'll love APL,[1]
where Conway's Game of Life[2] can be written in one line as:

    
    
      life←{↑1 ⍵∨.∧3 4=+/,¯1 0 1∘.⊖¯1 0 1∘.⌽⊂⍵}
    

[1] - <https://en.wikipedia.org/wiki/APL_(programming_language)>

[2] - <https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life>

~~~
vidarh
We also want our code to be _readable_.

~~~
_ZeD_
I think a really simple rule-of-thumb for code is: "can you dictate it through
the phone?"

~~~
vorg
Code has nested structures which are commonly shown with indentation, which
it's difficult to communicate vocally with say, intonation. E.g. think about
how differently you'd dictate this variation on your reply...

I think a really simple rule of thumb-for-code is "can you dictate it?"
through the phone.

------
dons
> A few years back, one big lure of Python or Ruby used to be the functional
> constructs that they offered like higher order functions.

This statement surprises me.

~~~
steveklabnik
Why's that, dons? They are playing a bit fast and loose with what 'higher
order functions' means, but, for example, one of Ruby's best features is
blocks. The details of higher order stuff in Ruby is certainly... messy, but
blocks are a great introduction to the concept for people who haven't used
them before. I've taught the concept to high school kids on their first day of
programming, (mostly through a physical metaphor involving a list of chores on
a piece of paper) and they picked it up easily enough.

~~~
sixbrx
I can't speak of Ruby (or for Dons :), but I'm not sure Python's use of hof's
is a good example to learn from when it's lambda scoping rules produce such
"interesting" results.

>>> monomials = [lambda x: x(star)(star)i for i in [1,2,3]] #(not sure how to
escape stars for exponentiation properly, whatever)

OK, what will these functions evaluate to at the point 2.0?

>>> monomials[0](2.0), monomials[1](2.0), monomials[2](2.0)

(8.0, 8.0, 8.0)

The i variable was captured as an address which all the lambdas share. For an
_integer_. Ouch.

You can do "lambda x,i=i: x(star)(star)i" and capture the value properly, but
to me this is a landmine waiting to be stumbled upon every time I write a
lambda. I for one will often forget to do this, at least so long as I also
keep using other languages which can capture integers as _values_ without
hijinks.

~~~
east2west
I wonder if anyone knows why subtlety exists in Python. Is it because
reference semantics and HOF are fundamentally incompatible, or could it have
been avoided somehow but still retaining reference semantics. The most common
complain about lambda in Python is that it is restricted to expressions, which
is a conscious design decision that could have gone the opposite direction.

~~~
halter73
The subtlety sixbrx mentions used to be present in C#, but it has been mostly
fixed by moving the declaration of the foreach loop variable inside of the
loop [1]. Like Python, C# has reference semantics. I'm surprised that Guido
van Rossum didn't make a similar change when he broke backwards compatibility
in Python 3.

[1][http://blogs.msdn.com/b/ericlippert/archive/2009/11/12/closi...](http://blogs.msdn.com/b/ericlippert/archive/2009/11/12/closing-
over-the-loop-variable-considered-harmful.aspx)

------
viraptor
I agree with his view, but I could never find a static typed language that was
useful in a long run.

Haskell was amazing as long as try don't need to do much io. When I started
spending more time fighting the constraints than being productive I stopped.

Ocaml was also not bad. But their strict restrictions on what opetators can be
used with what types is annoying when you do lots of calculations. Having to
explicitly cast numbers all the time was not inviting either.

Rust sounds great, but after a day of playing with it I saw it's really not
ready yet. A couple of places needed wrapping in "unsafe" block to start
working as expected. Some keywords and ideas were also going to change soon. I
couldn't get used to the restrictions coming from not having exceptions or
early function returns. It really adds some maintenance code.

Scala was probably the best so far, but the heavy vm is annoying.

So... still waiting for that perfect language.

~~~
anon1385
>I couldn't get used to the restrictions coming from not having exceptions or
early function returns

I'm probably being getting confused about what you mean here, but I thought
you can return from anywhere in a function in rust using 'return'. I think
Option types are one way to propagate errors back up the stack (with the
compiler forcing you to handle them), but I don't know how practical that is
in reality.

I agree that Rust isn't ready for production use though, even in the few weeks
I've been trying it they have decided to change parts of the language. Also
the standard library is lacking in documentation and is pretty inconsistent.

~~~
viraptor
What I mean is that if you don't have exceptions and `return` returns only
from a given block, it takes some serious exercise to break out of a "fn ... {
...each { ... match ... } } }".

Return will only return from one of them, so to signal an error from the match
block, you need to:

\- save the result in a mutable variable in a function

\- do something that results in "false" returned from each block

\- return the result from the function (probably casting mut->immut on the
way)

What I'd really like is either a stack unwinding exception, or a `return`
keyword that's different from the "last expression in a block" syntax. Last
expression could give a result for a closure, match, if, etc. while `return`
could always break out of a function. For example (pseudo-code, proper syntax
doesn't matter here):

    
    
        fn parse_into_list(s: &str) -> Option<Stuff> {
            let res = do s.map |c| {
                match c {
                    bad_character => return None
                    ...
                }
            }
            Some(Stuff(res))
        }
    

Instead of:

    
    
        fn parse_into_list(s: &str) -> Option<Stuff> {
            let mut result: ...;
            let mut correct: true;
            do s.each |c| {
                match c {
                    bad_character => {correct = false; false}
                    good_character => { do_stuff_with_result; true}
                }
            }
            if correct {
                Some(Stuff(result))
            } else {
                None
            }
        }

------
mseepgood
The title should have been "My personal comeback to static typing", because
static typing was never gone.

~~~
rschmitty
well if you read HN religiously you might have thought otherwise

------
jmount
I have distilled my thoughts on this down to: if you think dynamic typing is
the only effective way to do things you probably have never done any
significant debugging or maintenance. Dynamic typing is a solution, but like
all solutions it has limits. Here is my longer article on the topic before I
distilled down to the above: [http://www.win-vector.com/blog/2012/02/why-i-
dont-like-dynam...](http://www.win-vector.com/blog/2012/02/why-i-dont-like-
dynamic-typing/) .

------
randomfool
Disagree that static typing is important- it's all about static analysis.
Static analysis has come a long ways for dynamic languages, see TypeScript or
the Closure JS compiler for example.

~~~
gnuvince
Static analysis is a great tool, but the guarantees of a typing system can be
much stronger (and as a result, can inform the static analyzer much better).

~~~
randomfool
A typing system != static typing!

Static typing means that the types cannot change. Dynamic languages can still
declare types. It's just that they are allowed to morph. A good analyzer can
track those changes and know when types are equivalent (TypeScript does this).

Furthermore, typing is one mechanism to express contracts within your code-
such as 'this method takes argument X which is of the form Y and will return
something which looks like Z'.

More complex analysis requires more and more annotations to specify the
contracts of the methods. An example is a C function which takes a char* and
an int. You want to annotate that the int indicates the length of the char*
buffer, and have a static analyzer enforce that.

I am _all_ about code contracts and enforcement of those contracts. But this
is not necessarily tied to a static language.

~~~
Peaker
There's just a different set of terms used here.

In static typing context, "types" is a lexical construct of subexpressions. In
this context, dynamically typed languages are "untyped" or "unityped" (one
type for all expressions).

In dynamic typing context, "types" are the runtime tags of data with rules
about dispatch and what kinds of tags are allowed with what operations.

I think for the benefit of communication, we should refer to the static,
compile-time annotation on sub-expressions as "types", and the entity dynamic
languages calls "types" as "tags".

Your example:

> More complex analysis requires more and more annotations to specify the
> contracts of the methods. An example is a C function which takes a char* and
> an int. You want to annotate that the int indicates the length of the char*
> buffer, and have a static analyzer enforce that

This is of course certainly compatible with types. Something like:

    
    
        func : (n : Int) -> Ptr (Array n Char) -> ...
    

This is the type of the contract you specified.

Static types and static analysis are basically variants on the same idea.
However, static types is part of the ordinary workflow, and static analysis is
often treated as an "after-the-fact" feature. This will not work as well,
since much of the power of types relates to techniques to structure our
programs so that types cover as much as possible.

------
rcirka
One of the points the author makes, is that static typing improves code
maintainability and refactoring. I've used both static and dynamic languages.
When I was younger I preferred dynamic typed because they were easier to start
with and code, but now that I've grown more experienced and dealt with highly
complex projects, I prefer static typed. Being able to debug, maintain, and
refactor code is much easier and less risky in static typed languages.

------
Spykk
I think dynamically typed languages have become so popular because in simple
examples they look great to novices. You don't need to know much syntax about
defining variable types, you don't have to type as much, you don't have to
figure out why adding an integer to the end of your string won't work, etc.
Later, when they try to build something large enough to be useful they realize
just how much they traded for that little bit of convenience. For example in
PHP:

    
    
      $id = 1;
    
      $dbh = new PDO($connectionString, $user, $password);
    
      $sql  = ' SELECT column';
      $sql .= ' FROM table';
      $sql .= ' WHERE id = :id';
    
      $stmt = $dbh->prepare($sql);
      $stmt->bindParam(':id', $id);
    
      if($stmt->execute()) {
        // Do stuff
      }
    
      //This echos ID: 1
      echo "ID: $id";
    
      if($id === 1) {
        echo 'This should be true, we set $id = 1 at the top.';
      } else {
        echo 'Instead we get here because PDO casually changed our variable into a string and "1" != 1.';
        die('in a fire dynamic typing.');
      }

~~~
ScottBurson
> you don't have to figure out why adding an integer to the end of your string
> won't work

You're confusing dynamic typing with weak typing. A language can be
dynamically typed (types are checked at runtime) without doing things like
automatically converting integers to strings, integers and strings to
booleans, etc. etc.

Conversely, a language can be statically typed and still do some of those
conversions.

------
sokrates
I very much like Go's approach to static typing. Go allowed me to retain the
flexibility and ease of development that Ruby and friends provide, even though
the output is fully statically typed. It's great!

~~~
Peaker
HM type systems have been providing this benefit (to a greater effect than Go)
for ~40 years...

~~~
pjmlp
That is Go's PR on the move, presenting Go features as novelty.

My personal one is how fast it compiles, given I was doing the same thing with
Modula-2 and Turbo Pascal in the mid-80's.

------
tewolde
For the dev building the library static typing is a very convenient thing to
have. All the ins and outs have very clear rules enforced at compile level.

However, for the user of the library, it simply gets in the way. This may be
avoided though if the library has been designed well enough that strange
internal types are not exposed to the user unless absolutely necessary.

~~~
tikhonj
Actually, I find the opposite to be the case--static typing helps me use
unknown libraries. The types immediately let me know exactly what a function
expects and what I should expect from a function. They also prevent me from
using things incorrectly most of the time.

Essentially, the types are compiler-enforced documentation. They also make
discovering functions easier--a type is a succinct summary of what a function
does, so I can just browse by types to find what I want quickly. Augment this
with great tooling like Hoogle (a type search engine) and you've got a truly
awesome development system.

------
berlinbrown
I am sure you don't care but Scala runs on the Java virtual machine.

