
Revenge of the Types - rwosync
http://lucumr.pocoo.org/2014/8/24/revenge-of-the-types/
======
ak217
Of all Armin's articles to date, this one I agree the most with.

> Python is a language that suffers from not having a language specification
> ... There are so many quirks and odd little behaviors that the only thing a
> language specification would ever produce, is a textual description of the
> CPython interpreter... Keeping a language lean and well defined seems to be
> very much worth the troubles. Future language designers definitely should
> not make the mistake that PHP, Python and Ruby did, where the language's
> behavior ends up being "whatever the interpreter does".

This is an incredibly important point. The rise of PyPy is just one compelling
illustration of how Python is at a point where a language specification is
needed, and these crazy CPython-specific bugs need to be purged.

> I think for Python this is very unlikely to ever change at this point,
> because the time and work required to clean up language and interpreter
> outweighs the benefits.

I would disagree - I think it's possible for Python to change this. Any such
bizarre behaviors need to be treated as a bug, and eliminated in the next
release.

~~~
rcthompson
What are good examples of languages with specifications and at least two
implementations that fully implement the spec?

~~~
chaoky
Common Lisp, for sure

~~~
rcthompson
Yes, the various Lisps were the first possible examples I came up with (I
think Scheme probably qualifies as well).

------
gordaco
"Because there is basically no type system that fights against you, you are
unrestricted in what you can do, which allows you to implement very nice
APIs."

If you feel like the type system fights _against_ you, chances are that you
are doing something wrong. When I program, the type system definitely fights
_for_ me. It gives me a lot of guarantees, plus it's a really convenient way
of self-documentation. I mean, I'm not even talking about Haskell or something
really sophisticated: I see the advantages even in old plain Java or C++ (so
much that, in fact, most of my gripes about Java are about its type system not
being complex enough).

Also, being "unrestricted" is far from being an universally good thing, since
it also means many more opportunities for mistakes. I know for a fact that I
make more mistakes in languages without static typing, but well, I guess it's
just me.

~~~
eric_bullington
>If you feel like the type system fights against you, chances are that you are
doing something wrong.

Like most things, I think this depends on context. Doing exploratory data
analysis in a static, strongly-typed language, for example, is extremely
painful. And writing quick, one-time scripts in such languages is usually more
trouble than it's worth. For this reason, Python is a wonderful language for
doing data analysis and writing quick one-time data munging scripts (and yes,
I realize that Python can be considered strongly-typed).

On the other hand, I've now been exposed to languages like OCaml and Rust, and
have had time to think about Java, and I now have a different attitude when
I'm building a large application that will have to be maintained. I'm
beginning to feel _extremely_ vulnerable when I use a language like Python or
(worse yet) Javascript to build such applications.

It's not that I'm not a Javascript hater. I _like_ Javascript in general -- it
has a kind of functional feel to it, it's easy to prototype quickly, you can
use it client and server, nice ecosystem, and unlike so many I actually
_enjoy_ async programming. And I've long enjoyed Python for similar reasons.

But for building a robust application that will have to be maintained a long-
time, you have to religiously write tests in these languages or you'll be
buried in bugs. And even then, you _still_ may be buried in bugs that a
static, strongly-typed language would have detected. For this reason, I'm
looking hard for an static, strongly-typed alternative to Javascript for the
browser (i.e., a language compiling to JS) for building large applications.
And Ocaml's js_of_ocaml is definitely on my list of things to evaluate.

So the programming language philosophy that I adhere to now is encapsulated in
the hackneyed old saying "use the right tool for the job".

~~~
jshen
"But for building a robust application that will have to be maintained a long-
time, you have to religiously write tests in these languages or you'll be
buried in bugs. And even then, you still may be buried in bugs that a static,
strongly-typed language would have detected."

People make this sort of claim all the time, but my personal experience has
not borne it out, and I have seen no data to backup this claim which would
override my personal experience.

First, I find I have to write tests nearly as religiously in statically types
languages, so I don't find that a convincing argument.

Second, most bugs I've experienced in large code bases using a dynamic
language are not the sort that would be caught by most typed languages. On
this point there is even some data that backs up my personal experience
([http://vimeo.com/74354480](http://vimeo.com/74354480)).

Third, writing code with a static language takes more time in my experience.
Maybe it prevents a tiny fraction of bugs, but for most things I'll take
saving significant time and cost over preventing 3% of bugs (I made up that
number).

In short, I'm not sold on these arguments for static typing.

~~~
loup-vaillant
Funnily enough, my experience has been quite the opposite.

I never felt the need for TDD or such… until I used Lua. I was drowning in
bugs for a tiny 200 lines program! I just couldn't finish. Then I wrote some
visualization code, then more of it, until I had the equivalent of a domain
specific debugger. It worked. I found my mistakes, and corrected them. Then I
though " _that_ is where TDD comes from".

A statically typed languages such as Ocaml or Haskell would have caught the
vast majority of my mistakes right away. Heck, even C++ would have helped. In
my experience, writing code that "mostly works" is _faster_ with a statically
typed language. So many trivial tests you don't have to write, so much
debugging you don't have to do…

> _Second, most bugs I 've experienced in large code bases using a dynamic
> language are not the sort that would be caught by most typed languages._

So, no Null pointer bug?

Also don't underestimate the number of domain logic errors that could have
prevented by encoding the domain logic into the type system. Type systems can
encode _many_ invariants, they're not limited to "this is a bool, I wanted an
int".

~~~
jshen
I always wonder, if languages like Haskell are so good, why don't we see a lot
of amazing open source projects built with these languages? If you can get
things done faster with fewer bugs it should be reflected in real life code
bases. Yet I haven't seen it.

"The only arguments that hold water, in terms of programming language
suitability, are bold, finished projects."
[http://t.co/ahOBAnXZ18](http://t.co/ahOBAnXZ18)

~~~
Joeri
Programmers write the same number of debugged lines (or expressions) of code
per day, regardless of the language they write in. A language only enables
faster development if it requires fewer expressions to say the same thing.
That is why high-level languages trounce low-level languages when it comes to
productivity. I admit to not being very familiar with Haskell, but if it is
not more concise it's not likely to be more productive.

~~~
NateDad
I don't believe that. The speed of producing code is not relative to typing
speed. LOC per day depends on the complexity of the lines. I can write 500
simple lines or 50 complex lines of code in a day. I'd agree that higher level
languages deal with some of the complexity for you, like memory management.
But I bet the business logic takes a similar amount of time in almost any
language, assuming the developer has the same amount of experience in each
language.

~~~
jshen
The way to reduce lines of code is to create good abstractions. Some languages
may be better at this than others, and I think this is more important than the
type system of the language.

~~~
dllthomas
In some languages, the type system helps quite a bit in creating abstractions.

~~~
jshen
I doubt it makes it easier to create abstractions compared to a lisp.

~~~
dllthomas
There are upsides and downsides to working in something with a sufficiently
useful type system versus working in a lisp - even as pertains specifically to
abstractions.

You can doubt, but I'm speaking from some experience with both. That doesn't
necessarily mean I'm right, of course, but take it for what it's worth.

------
bjourne
Armin didn't address what I belive is the main point of adding type
annotations to Python: compiler checkable documentation and as hints to IDE:s.
Seen in that perspective, a sucky type system is good enough because it's use
isn't to verify program correctness. Personally, I think a standardized format
for describing types in docstrings would be 100x better but that's not the way
the Python core devs have choosen.

Another argument in favor of types is that it will enable Python to optimize
code better. But since Python isn't built for static typing, the CPython
bytecode interpreter has no facilities for exploiting the extra information.
And even if it had, the V8 Javascript VM proves that you dont need static
types to generate optimized code.

~~~
randlet
On the topic of IDE's, WingIDE has an interesting approach where you can add
`assert isinstance(your_var, SomeClass) to the beginning of your functions to
help Wing analyse your code[1]. It's more verbose than type annotations and
doesn't feel very idiomatic sprinkling asserts all through your code but I
recall it being pretty helpful (I haven't used Wing in years now).

[1] [https://wingware.com/doc/edit/helping-wing-analyze-
code](https://wingware.com/doc/edit/helping-wing-analyze-code)

~~~
andreif
Sometimes I do it in PyCharm as well when it has troubles auto-detecting
types.

~~~
int_19h
PTVS supports it, as well. Basically, this is the way to go if you want cross-
IDE type hints right now.

------
pixelmonkey
Some people may not understand the context of this part:

    
    
        So not long ago someone apparently convinced 
        someone else at a conference that static typing
        is awesome and should be a language feature. I'm 
        not exactly sure how that discussion went but the
        end result was that mypy's type module in combination
        with Python 3's annotation syntax were declared to be
        the gold standard of typing in Python.
    

Ronacher is referring to the fact that Guido van Rossum, the Python language
creator and BDFL, recently said he wanted to make mypy's type annotation
standard into a standard by making use of Python 3 function annotations.

The original function annotations standard is PEP-3107[1], GvR's proposal is
on the python-ideas list[2], and information on mypy can be found at the
project's site[3].

I agree with Ronacher's conclusion; I don't think static types -- even if only
used at runtime -- are a good fit for the language. As for function annotation
syntax, I think we just need to admit that isn't really good for anything.

Great article!

[1]:
[http://legacy.python.org/dev/peps/pep-3107/](http://legacy.python.org/dev/peps/pep-3107/)

[2]: [https://mail.python.org/pipermail/python-
ideas/2014-August/0...](https://mail.python.org/pipermail/python-
ideas/2014-August/028618.html)

[3]: [http://www.mypy-lang.org/](http://www.mypy-lang.org/)

~~~
keypusher
The thing that function annotation syntax is good for is the ability to catch
errors before they hit your production server at 2AM on a Tuesday. If you can
describe the types that a function accepts and returns, violations of those
rules can be caught by static analysis such as pylint and let you know before
you commit. The current approach in Python after refactoring a large chunk of
code is to grep through all the existing callers, fix what you can find, run
the tests and hope for the best.

------
Cyther606
I've been using Nimrod to replace Python on a Bitcoin project.

elliptic.nim:
[https://github.com/def-/bigints/blob/master/examples/ellipti...](https://github.com/def-/bigints/blob/master/examples/elliptic.nim)

elliptic.py:
[https://github.com/wobine/blackboard101/blob/master/Elliptic...](https://github.com/wobine/blackboard101/blob/master/EllipticCurvesPart4-PrivateKeyToPublicKey.py)

Nimrod looks and feels like python, but it compiles to C. It's like C except
with Pythonic syntax and with Boehm GC optional. In addition, Nimrod has a
burgeoning NPM-like module ecosystem developing, albeit in the early stages.

    
    
        import rdstdin, strutils
        
        let
          time24 = readLineFromStdin("Enter a 24-hour time: ").split(':').map(parseInt)
          hours24 = time24[0]
          minutes24 = time24[1]
          flights: array[8, tuple[since: int,
                                  depart: string,
                                  arrive: string]] = [(480, "8:00 a.m.", "10:16 a.m."),
                                                      (583, "9:43 a.m.", "11:52 a.m."),
                                                      (679, "11:19 a.m.", "1:31 p.m."),
                                                      (767, "12:47 p.m.", "3:00 p.m."),
                                                      (840, "2:00 p.m.", "4:08 p.m."),
                                                      (945, "3:45 p.m.", "5:55 p.m."),
                                                      (1140, "7:00 p.m.", "9:20 p.m."),
                                                      (1305, "9:45 p.m.", "11:58 p.m.")]
        
        proc minutesSinceMidnight(hours: int = hours24, minutes: int = minutes24): int =
          hours * 60 + minutes
        
        proc cmpFlights(m = minutesSinceMidnight()): seq[int] =
          result = newSeq[int](flights.len)
          for i in 0 .. <flights.len:
            result[i] = abs(m - flights[i].since)
        
        proc getClosest(): int =
          for k,v in cmpFlights():
            if v == cmpFlights().min: return k
        
        echo "Closest departure time is ", flights[getClosest()].depart,
          ", arriving at ", flights[getClosest()].arrive

~~~
progman
Nice features:

[http://ivoras.sharanet.org/blog/tree/2013/Oct-2013-10-05.wha...](http://ivoras.sharanet.org/blog/tree/2013/Oct-2013-10-05.what-
i-like-about-the-nimrod-programming-language.html)

Type inference:

[http://nimrod-by-
example.github.io/variables/type_casting_in...](http://nimrod-by-
example.github.io/variables/type_casting_inference/)

Quick introduction for C programmers:

[https://github.com/Araq/Nimrod/wiki/Nimrod-for-C-
programmers](https://github.com/Araq/Nimrod/wiki/Nimrod-for-C-programmers)

------
pjungwir
Random question for the type experts out there: is there any language that
lets me track the units of my numeric variables? For instance, something like
this:

    
    
        float<km> drop(float<m> x0, float<s> duration) {
          float<m> x = x0;
          float<s> t = 0;
          float<m/s> v = 0;
          float<m/s^2> g = -10;
          float<s> dt = 0.01;
          while (t < duration) {
            v += g*dt;
            x += v*dt;
            t += dt;
          }
          return x * (1<km>/1000<m>);  // abbrev for a cast: (float<km/m>).001
        }
    

Then I want the compiler to check that I'm not mixing up my units. It seems
like this would be really useful, but I've never seen it before.

~~~
tikhonj
Haskell has a few libraries to do this. I particularly like unittyped[1],
which not only keeps track of units but also converts among compatible ones
automatically. So 1 meter + 1 inch would typecheck and be converted
automatically, but 1 meter + 1 second would give you a type error.

The wiki page[2] has a bunch of examples, which I find pretty compelling. The
one problem is that error messages are ugly, but they're ugly in a consistent
way. You can just ignore the ugliness as unnecessary noise.

    
    
        *Main> (1 meter / second) * 5 second
        5.0 m/s⋅s
        *Main> 2 meter + (1 meter / second) * 5 second
         7.0 m
    

One cute thing is that prefixes like "kilo" are just functions, letting you
write things like:

    
    
        *Main> (42 kilo meter) `as` mile
        26.097590073968025 mile
        *Main> gallon `as` (cubic (deci meter))
        4.546089999999999 dm⋅dm⋅dm⋅#
    

Haskell is really good at dealing with numeric types in general. For example,
it's quite easy for a library to define its own types, which then behave just
like built-in ones including nice syntax. Unittyped follows this philosophy,
letting you use units with things that aren't floats, like rational numbers,
meaning you don't have to lose precision.

    
    
        *Main>  (1 % 2) . meter `as` foot
        625 % 381 ft
    

It's a really slick design and manages to give you safety _as well_ as
additional expressivity (since units get converted automatically).

[1]:
[https://hackage.haskell.org/package/unittyped](https://hackage.haskell.org/package/unittyped)

~~~
berdario
I'm not sure why, but your examples aren't working with me...

    
    
        1 *| meter |+| 35 *| centi meter
        1.35 m
    

works, but

    
    
        1 meter
    

fails with

    
    
        <interactive>:42:1:
            No instance for (Num (Value LengthDimension (U Meter) f0 -> t0))
              arising from the literal `1'
            Possible fix:
              add an instance declaration for
              (Num (Value LengthDimension (U Meter) f0 -> t0))
            In the expression: 1
            In the expression: 1 meter
            In an equation for `it': it = 1 meter
        
        <interactive>:42:3:
            No instance for (Fractional f0) arising from a use of `meter'
            The type variable `f0' is ambiguous
            Possible fix: add a type signature that fixes these type variable(s)
            Note: there are several potential instances:
              instance Fractional Double -- Defined in `GHC.Float'
              instance Fractional Float -- Defined in `GHC.Float'
              instance Integral a => Fractional (GHC.Real.Ratio a)
                -- Defined in `GHC.Real'
              ...plus four others
            In the first argument of `1', namely `meter'
            In the expression: 1 meter
            In an equation for `it': it = 1 meter

~~~
gizmo686
Try running "import UnitTyped.NoPrelude" first.

    
    
      EDIT: you may also want to start ghci with the "-XNoImplicitPrelude" flag, or explicitly disambiguate operations such as "*" with "UnitTyped.NoPrelude.*" or "Prelude.*"

~~~
berdario
Thanks, but that's not enough. The error seems due to the fact that `meter` is
passed as an argument to `1` which is not a function, and indeed I don't see
how that could be valid haskell code (unless there's some language flag I
should enable, but unfortunately the wiki/docs of unittyped doesn't seem to be
comprehensive enough)

~~~
gizmo686
Weird, it is enough on my machine (running ghc 7.6.3, unittyped 0.1), but
unittyped does seem to use a lot of language extensions internally, it is
seems possible that it would behave weirdly on different versions.

To answer the question of how it is possible, we can start by looking at the
types. ":t" is a ghci command to show the type of an expression:

    
    
      ghci> :t 1
      1 :: Num a => a
    

This indicates that "1" can be any type that implements the "Num" typeclass.

Next, we want to determine what type "1" takes in the expression "1 meter". We
can do this with:

    
    
      ghci> let a=1; b=a meter
      ghci> :t a
      a :: UnitTyped.Value Double LengthDimension Meter
         -> UnitTyped.Value
              Double
              ('UnitTyped.UnitCons
                 * Length ('UnitTyped.Pos 'UnitTyped.One) 'UnitTyped.UnitNil)
              Meter
    

We can see that, in the expression "1 meter", "1" is actually a function.
Looking at the source code [1], it seems like this is accomplished in a
relativly hacky manner:

    
    
      instance (Fractional f, Convertable a b, t ~ Value f a b) => (Prelude.Num (Value f a b -> t)) where
    	fromInteger i x = Prelude.fromInteger i . x
    	(+) = error "This should not happen"
    	(*) = error "This should not happen"
    	abs = error "This should not happen"
    	signum = error "This should not happen"
    

This works because the "+" being defined here is Prelude.+, not
UnitTyped.NoPrelude.+ (which is defined seperatly).

[1]
[https://hackage.haskell.org/package/unittyped-0.1/docs/src/U...](https://hackage.haskell.org/package/unittyped-0.1/docs/src/UnitTyped-
NoPrelude.htm)

~~~
berdario
I see. I tried to report this as a bug, fwiw:

[https://bitbucket.org/xnyhps/haskell-
unittyped/issue/3/num-i...](https://bitbucket.org/xnyhps/haskell-
unittyped/issue/3/num-instance-isnt-imported)

Btw, it's weird... I just tried

    
    
        ack-grep "Num\b"
    

and I cannot see any instance of Num defined anywhere inside unittyped's src

PS: ok, since I wanted to see exactly what was the problem with unittyped
compiling under ghc7.8 I cloned the sources, but I forgot to checkout the
actual release... thus running directly from tip was the cause

Installing it directly from hackage solved it, it's embarrassing how I was
stunned by this in hindsight

------
aikah
We live in that wonderfull time in development,where a lot of things are
questioned.A lot of languages that used to rule everywhere are questioned,like
the OP,and devs try to come up with the ultimate language that would solve
every use case.

There is,of course, no such a language but future languages wether they are
dynamic or static ,strong or weak (type wise) will certainly not make the same
mistake as their ancestors.

Personally I want a scripting language,with type inference but real strong
static typing, that can be easily interfaced with C++, that handles
concurrency the right way(ie not like javascript callbacks),that is trully
multipurpose(like python) elegant(a bit like ruby), 00 with composition and
strong encapsulation in mind and access modifiers, with immutable structures
and variables by default but not limited to it,with some functional features
without looking like Haskell,resonably fast for GUI dev,scientif computation
and non trivial web apps,easy to deploy on a server, with sane error
handling,IO streams everywhere, a clear syntax(no unreachable characters on
non english keyboards everywhere),with a good package manager, an interactive
repl(like IPython or the tool for swift,I forgot the name) and with battery
included.

So we are definetly living in an exciting period.

~~~
1_player
I don't think C++ interface is easily feasible, as far as I know no language
managed to do that yet, probably because of the wildly different ABI between
C++ compilers.

Anyway, I would add to your list Go concurrency constructs (channels,
"go"-like statements), polymorphic types, and, personally, significant
whitespace for indentation, like Python.

Rust is a big step in the right direction, although it's a bit too
complex|heavy for scripts.

------
arthurdenture
The argument seems to be that if the added type system is not perfect, then it
will be useless. For a working counterexample, see the Closure Compiler
([https://github.com/google/closure-
compiler](https://github.com/google/closure-compiler)), which adds a bolt-on,
underspecified, occasionally-changing type system to Javascript. Similarly to
GvR's proposal ([https://mail.python.org/pipermail/python-
ideas/2014-August/0...](https://mail.python.org/pipermail/python-
ideas/2014-August/028618.html)), the types are only ever checked at compile
time: there's no attempt to use them as runtime assertions and very limited
attempts to use them for compile-time improvements. So, yes, because they are
imperfect and optional, you don't catch every type error, and you need to add
type hints / casts that in a perfect system wouldn't be necessary.

Is this kind of flawed type system worth it? Hell yes. I've maintained large
programs in both Python and (closure-compiled) Javascript, and with the former
I've wished I had the help of the limited type checking available in the
latter.

------
tosh
If you want to learn more about how 'optional' and 'unsound' type systems can
still deliver a lot of value there are some interesting articles on Dart's
optional types:

* [http://journal.stuffwithstuff.com/2011/10/21/wrapping-my-hea...](http://journal.stuffwithstuff.com/2011/10/21/wrapping-my-head-around-optional-typing/)

* [https://www.dartlang.org/articles/why-dart-types/](https://www.dartlang.org/articles/why-dart-types/)

* [https://www.dartlang.org/articles/optional-types/](https://www.dartlang.org/articles/optional-types/)

------
cygx
I find it interesting that this is exactly what Perl6 tried to handle
gracefully, both on the technical side (a type system that supports both
static and dynamic typing) as well as on the practical side (a re-
implementation from scratch with some measure of interoperability).

However, they did not set out to just design the next version of Perl, but the
_last_ version, reasoning that if you have proper extension mechanism in
place, you won't have to do a reboot ever again.

This resulted in gradual typing (which sometimes needs to fall-back to runtime
checks), a pluggable syntax with extensible grammar, a flexible meta-object
protocol, default numeric types that are objects (rationals or bigints), lazy
list, reified language construct (variables as container objects) and other
stuff that makes a straight-forward implementation horribly slow.

------
ivoras
Not only that, but look at the niche Python is occupying. It's a well
established and respected niche to which, by definition, the language is
suited very well.

By adding static types, the focus of the language would move to a different
niche, which would probably be already occupied by some competitor language(s)
which do(es) types much better.

If you want sort-of Python-ish syntax with elaborate types, just use Nimrod
and leave Python alone. Get the right tool for the job, don't mutilate a
perfectly good existing tool.

~~~
hyperpape
What exact niche is that? Unless you mean "dynamically typed" (in which case
that begs the question), I don't know what niche you think it couldn't occupy
with static types. Not even arguing for static types: your comment is just
really unclear.

------
Jweb_Guru
Hrm. I think this article does a great job of explaining weird inconsistencies
in Python's current type system, but I think it does a somewhat less good job
of demonstrating that adding annotations is actively harmful. What would be
some examples of situations where inconsistencies in the type system made
annotations problematic in practice? Are those situations compelling enough to
warrant not adding _any_ annotations to the language?

------
fish2000
Python's API structure may be fast and loose, but that is a feature, I think.
Its type system may have some threadbare implementation spots – the _sre
example from the standard library, for instance – but there are some
compelling examples as well.

I, for one, have been working on an app implemented mostly with PyObjC, the
bridge between Python and Objective-C. I had all but written off PyObjC as a
bizarre yet unuseful language mule... but lately I had the occasion to read
through the PyObjC source code base, in service of my project. Did you know
that when you subclass a wrapped Objective-C type in Python, an all-new
Objective-C class is created and wrapped as the descendant class, behind the
scenes? That blew my mind.

That happens transparently, in concordance with Python's type heiarchy and
runtime ABI. As it turns out, PyObjC predates Mac OS X, and the authors have
put a lot of work into mitigating things like the GIL and system events.

I am also a fan of Django's field type system, as the author mentioned – and I
am curious about what he thinks about descriptors (which he mentioned one but
did not address) – I think descriptors are an amazing addition to the duck-
typing regime in Pythonville.

------
tiffanyh
Lua

The more I read Armin's posts, the more I believe he should switch to Lua. It
has all the core features he wants:

\- simple design

\- fast

\- consistent behavior

In addition to what's mentioned above, LuaJIT is a marvelously designed JIT
(please donate to the project [1]. Let's keep allowing Mike Pall to have a
livelihood)

[1] [http://luajit.org/sponsors.html](http://luajit.org/sponsors.html)

------
wirrbel
This is a very nice article showing some of the issues troubling python and
the proposed type anotations.

I would summarize my view of the type annotation proposal as follows:
Statically typed languages can introduce inference heuristics that minimize
the amount of type declarations. They can "jump" into the dynamically typed
world more easily. The other way around is a lot harder. Not only are all
those type annotations lacking in the standard library and the tools around,
but there is also a lack of function design by types.

~~~
rurban
No, it's a horrible article. And no, they cannot. I implemented such a type
inferencer for perl (B::CC), which has the exact same problem.

With a highly dynamic run-time which changes the types at will, the compiler
will never be able to do proper optimizations without explicitly forbidding
certain coercions. The inferencer has to give up in 90% of all cases.

Only with optional explicit types, esp. for loop counters and array members,
those operations can be efficiently optimized. Up to 2000% for the typical
array or loop benchmarks.

And no, a v8-style tracing jit also does not help in all cases. This kind of
run-time type caching has a huge overhead, and will always need an explicit
run-time check, and does not catch the typical type errors writing programs.
It helps with simple scripts, but not with programs.

You don't have to worry. If you don't like to use types, don't use it. Nothing
will change. It will only compile-time optimize and check the cases where
someone added the types.

Of course the standard library is free to add type-optimized versions later,
as e.g some Common Lisp's did with their arrays and vectors. But this was done
mostly in the compiler, not in the library itself.

~~~
wirrbel
You are right about optimizations, there are a lot of situations where type
annotations could greatly help the compiler. I just do not have the feeling
that performance optimizations in CPython are the reason for Guido's proposal.
It rather seems to be motivated for development tooling.

Is `for i in xrange(10000):` especially optimized in python at the moment? I
doubt it and those low hanging fruits could be tackled with some explicit
pattern matching. (I probably should do my homework now and dive into the
python source code).

------
ForHackernews
Can somebody explain in greater detail what this means:

> This is true for the CPython interpreter world, but not true for Python the
> language. That these are not the same things is disappointing but generally
> the case.

My understanding was that the CPython interpreter is considered the
"reference" implementation of Python, and that (except for bugs) it defined
Correct Behavior for Python-the-language.

------
sjy
If the author is reading this thread, I spotted this type-o:

    
    
      Type type claims that it's a subclass of object.

~~~
aidenn0
Is that a typo? I read that as '[The type named] "type" claims that it's a
subclass of object'

Compare to "Type integer claims that it's a subclass of number."

~~~
sjy
That makes sense. It's confusing though because "object" gets a monospace font
but "type" doesn't.

------
kylebgorman
My hope is that Guido's plan to incorporate the type declaration module
(`types`, a subcomponent of mypy) will encourage the Python team to clean up
the issues brought up in TFA.

------
mmagin
I didn't know Python users hate static typing so much.

~~~
ayrx
I don't "hate" static typing. I dislike the current proposal though, because
the proposed syntax is a horrible wart on top of a very elegant language.

~~~
johnmaguire2013
Do you mean aesthetically or the proposed specifications?

~~~
ayrx
Little bit of both actually.

If the primary motivation behind optional type checking is IDE hinting and
compile time checks I'd actually prefer a standard docstring format instead of
annotations.

------
jimmaswell
>So what's the solution? Not having null references and having explicitly
typed arrays.

Throwing the baby out with the bath water. Null types are extremely useful.

I don't get why the author claims the null type in C# is a form of "damage".
It's just said that it's bad, not why. The problem with None in python was
that you can't tell what it's supposed to be. In C# you know what type the
null is meant to be.

~~~
aidenn0
If you have ever programmed in a language with strict enforcement of something
like a "maybe" or "option" type then you'll see that it's fairly trivial to
have a separate type for a nullable pointer and a non-nullable pointer.

It is essentially brain-dead that the type Foo really means "Either a Foo, or
null" Failure to properly check for null is a source of many, many bugs, and
there is an almost trivial way (assuming you're creating a new language, like
C# was) to completely prevent it in statically typed languages that was well
known when C# was invented.

~~~
rurban
I don't see the issue. Armin went completely insane IMHO.

This problem is usually solved by expressing the type "Foo or Null" as Foo? in
such a gradually typed language. Maybe the critics should lookup the basic
type literature first.

Such posts will kill python. And this type of type critic already did kill
python for Google. (And kept perl 10 years behind)

~~~
the_af
If when the type of a function _F_ is "Foo or Null", you can express it as
something like

 _F(...): Foo?_

and if you're later forced to deal with such a value, Null cannot catch you by
surprise, then haven't you just rediscovered Option types?

If, on the other hand, "?" is just an operator you use on values that can be
null, to guard against an exception, this seems less useful. Are you going to
wrap every return value of every function call with it? What happens if you
forget? How can you know, at a glance, if a function may return a null value?

