47 comments

[ 2.5 ms ] story [ 112 ms ] thread
MyPy works surprisingly well once you add this in a few places: # type: ignore

The (now documented) --silence-imports option will remove the most frequent use for ignoring types though.

This project is very similar to TypeScript or Flow and I have found it provides a similar huge boost in reliability.

I am looking forward to the feature of strict optional types checking which will not treat None as a inhabited value of any type.
I don't try it yet but it remember me Groovy type system. It is a great feature.

No type checker was one of the bigger flaws in Python.

When in Groovy, I use type checker in public functions and APIs. It is a good communication tool.

In my opinion, Python is better than Groovy. This feature still make it better.

I've used Python a lot more than Groovy but one thing I find myself missing from Python and other scripting languages since I discovered Groovy is the ability for a standalone script to retrieve its dependencies on startup. What this means is that if you put

  @Grab(group='foo', module='bar', version='1.0.0')
at the top of randomscript.groovy you will have bar available to import by the time the script starts.
You could use:

import pip

pip.main(['install', 'bar'])

It's not this simple. That code will only work if you are root or in a virtualenv — and having to create a virtualenv manually contradicts the idea of a self-contained, standalone script that manages dependencies on its own. To install bar as a non-root user you will have to do

  import pip
  pip.main(['install', '--user', 'bar'])
which throws an error, e.g., if bar is already installed, meaning you will have to wrap the calls to pip.main() in a "try" block and differentiate between the types of errors they throw.

The above already makes it noticably less convenient for a script to manage its own dependencies. The killing blow, however, comes form the fact that pip won't let you install multiple versions of the same package in parallel: the most recently installed version overwrites the previous one. This means that a script that relies on a per-user package store can only be safe if it checks the version of every package it uses and replaces it if needed each time it is run. This can a take a long time and is error prone (what if your Internet connection goes down?) but the alternative is simply to deal with the brittleness.

I can see this being solved for Python but the solution will probably involve automatically creating and caching per-script virtualenvs. For now, though, something like PyInstaller (i.e., binaries) remains more practical if you want to distribute standalone Python scripts.

I am sorry I made a mistake. You are right. Thanks for the explanation.
Aiui Perl6's module related design elements allow for this though I don't know if anyone has implemented what you describe.

I'll be happy to discuss this further if anyone shows interest.

Apache Groovy's original use case was scripting, so there's many features like that which makes Groovy be Bash for the JVM. It was based on Beanshell originally, but with closures and collections syntax added. Just don't try building any actual systems with Groovy -- do that in a language designed from the ground up for performance, e.g. Java, Scala, or Kotlin.
s/missing from Python/missing in Python/
You might like to look at Scala. You can write in a very similar style to Groovy or Python, but you get a full first-class type system. Everything's checked, but with type inference so it rarely gets in the way if you don't want to write any types.
My problem with Scala is that it is more complicated than Python. I like Python simplicity.
Not sure Python is simpler ... except maybe "easier" to move should-be-compile-time failures to run-time. :-)
only wish the tooling, such as sbt, were not so lackluster.

python as a first language? no problem. scala as a first language? you've got to be kidding me...

They should also implement a generics/template system.

(Barking at the wrong tree intensifies.)

Eh? MyPy already implements generics. It would be a pretty useless type system otherwise since you couldn't give precise types to e.g. lists of ints.
is there such thing as a typed interpreted language? I mean one with a REPL, not Java.
Scala is strongly, statically typed with a REPL.
OCaml and Haskell both have interpreters.
Java is actually getting a REPL with Java 9.
> is there such thing as a typed interpreted language?

Of course. Examples:

    ▶ ocaml
            OCaml version 4.02.3
    # 9;;
    - : int = 9


    ▶ ghci
    GHCi, version 7.8.4: http://www.haskell.org/ghc/  :? for help
    Loading package ghc-prim ... linking ... done.
    Loading package integer-gmp ... linking ... done.
    Loading package base ... linking ... done.
    Prelude> 9
    9
    Prelude> :t 9
    9 :: Num a => a
    Prelude> 


    ▶ drracket
    Welcome to DrRacket, version 6.3.0.2--2015-10-28(-/f) [3m].
    Language: typed/racket; memory limit: 128 MB.
    > 9
    - : Integer [more precisely: Positive-Byte]
    9


    ▶ scala
    Welcome to Scala version 2.10.4 (OpenJDK 64-Bit Server VM, Java 1.8.0_91).
    Type in expressions to have them evaluated.
    Type :help for more information.

    scala> 9
    res0: Int = 9

There are even interpreters for C (http://www.drdobbs.com/cpp/ch-a-cc-interpreter-for-script-co...).

tl;dr: you can have a REPL in both statically and dynamically typed languages.

Python (and many others) is a typed interpreted language. It's not statically typed, but it is typed.
I think most (S)ML implementations have a repl. So does GHC AFAIR. It's really not uncommon :)
Kotlin has a repl
Presumably, ultimately, all languages are typed in some way. Otherwise, how would the interpreter (or whatever execution environment is relevant) deduce what binary data was what?

I think the question you mean -- which I'm also interested in the answer to -- is: How can a dynamically typed language be statically type checked? Presumably Hindley-Milner style inference doesn't/can't work. Do static analysers such as Mypy therefore trace the execution of the code until it finds something that conflicts? Are there cases where this approach won't work, either technically or practically?

Forth is what I would consider an untyped language. It deals with numbers on a stack in a way that it is totally up to the programmer to decide what they represent. One number may be a IEEE 754 number, an unsigned integer, a signed integer, the address of a string, a fixed-point number, a couple of ASCII characters etc.
Same deal with most forms of assembly language- the values you work with are just numbers, and the operations to which you apply them are what give them a particular meaning at a particular point in time- addresses, offsets, integers, booleans, etc. It's possible to argue that such languages are "unityped" rather than "untyped", but I think to do so is to produce such a loose interpretation of "types" as to be uninteresting.
> Otherwise, how would the interpreter (or whatever execution environment is relevant) deduce what binary data was what?

Via runtime tags, which are not the same as types.

Those were missing: Most lisps, perl6, cperl, php 7, ruby 3
(comment deleted)
Still no support for await / async :( Guido worked on asyncio and works on this tool, I was expecting more love.
Can the type information be consumed by a compiler like nuitka to produce fast binaries?
You might be more interested in Cython.
Cython is uglier and without type inference.

I wish we could just use mypy when we feel like making our code faster :/