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.
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.
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.
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.
> 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
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.
47 comments
[ 2.5 ms ] story [ 112 ms ] threadThe (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.
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.
import pip
pip.main(['install', 'bar'])
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'll be happy to discuss this further if anyone shows interest.
python as a first language? no problem. scala as a first language? you've got to be kidding me...
(Barking at the wrong tree intensifies.)
What are you talking about? MyPy has supported generics since before the 0.1 release: https://github.com/python/mypy/blob/v0.1.0/docs/source/gener...
(Typing is optional)
Of course. Examples:
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.
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?
Via runtime tags, which are not the same as types.
https://vimeo.com/74354480 linked to from: http://games.greggman.com/game/dynamic-typing-static-typing/ linked to from: https://news.ycombinator.com/item?id=10933524
I wish we could just use mypy when we feel like making our code faster :/
https://docs.python.org/3/library/typing.html
The PEP 484 proposal:
https://www.python.org/dev/peps/pep-0484/