oleksii.moskalenko@healthjoy.com
In the past the world was very clearly divided between interpreted languages with dynamic typing and ahead of time compiled languages with static typing. This is changing as new trends emerge.
I believe we're moving in a future with powerful type systems. I do not believe that this will be the end of dynamic typing but there appears to be a noticable trend of embracing powerful static typing with local type inference.
Armin Ronacher, author of werkzeug
If the only type systems I knew were C, C++, Java or Go I’d be Ruby Programmer.
Paul Snively, not a Ruby Programmer
Languages with good type system:
Rust, OCaml, Haskell?, Agda
def upgrade_customer(user):
assert isinstance(user, Customer)
user.hinted_method_name()
A type system is the most cost effective unit test you’ll ever have.
Peter Hallam, C# designer
from typing import NamedTuple, Tuple, Dict, List
Name = str
Duties = List[str]
Address = NamedTuple('Address', [('city', str),
('country', str),
('zip_code', str)])
Employee = Tuple[Name, Duties, Address]
EmployeeId = int
Employees = Dict[EmployeeId, Employee]
Erlang: TypEr & Dialyzer
-record(mam_msg,
{key :: mam_msg_key(),
time :: erlang:timestamp(),
route :: route(),
from :: ljid(),
to :: ljid(),
stanza :: xmlel()}).
...
-spec receive_stanza(jid(), jid(), jid(), xmlel()) -> ok.
receive_stanza(#jid{luser = U, lserver = S} = JID, From, To,
#xmlel{name = <<"message">>} = Stanza) ->
...
Clojure: core.typed
(ann summarise
(IFn [(U nil (NonEmptyColl Int)) -> Int]
[(U nil (NonEmptyColl Int)) Int -> Int]))
(defn summarise
([nseq] (summarise nseq 0))
([nseq acc] (if nseq
(* (summarise (rest nseq)
(inc acc))
(first nseq))
42)))
x = [] # type: List[Employee]
x, y, z = [], [], [] # type: List[int], List[int], List[str]
x, y, z = [], [], [] # type: (List[int], List[int], List[str])
x = [1, 2] # type: List[int]
with frobnicate() as foo: # type: int
# Here foo is an int
...
for x, y in points: # type: float, float
# Here x and y are floats
...
import http.client
errors = {
'not_found': http.client.NOT_FOUND # type: ignore
}
from typing import TypeVar, Iterable, Tuple, Callable
T = TypeVar('T', int, float, complex)
Vector = Iterable[Tuple[T, T]]
def inproduct(v: Vector) -> T:
return sum(x*y for x, y in v)
...
def async_query(on_success: Callable[[int], None],
on_error: Callable[[int, Exception], None]) -> None:
# Body
...
def first(l: Sequence[T]) -> T: # Generic function
return l[0]
def parse_statement(self) -> Tuple[Node, bool]:
stmt = Undefined # type: Node
t = self.current()
ts = self.current_str()
is_simple = True # Is this a non-block statement?
if ts == 'if':
stmt = self.parse_if_stmt()
is_simple = False
elif ts == 'def':
stmt = self.parse_function()
is_simple = False
elif ts == 'while':
stmt = self.parse_while_stmt()
is_simple = False
elif ts == 'return':
stmt = self.parse_return_stmt()
elif ts == 'for':
stmt = self.parse_for_stmt()
is_simple = False
elif ts == 'try':
stmt = self.parse_try_stmt()
is_simple = False
elif ts == 'break':
stmt = self.parse_break_stmt()
elif ts == 'continue':
stmt = self.parse_continue_stmt()
elif ts == 'pass':
stmt = self.parse_pass_stmt()
elif ts == 'raise':
stmt = self.parse_raise_stmt()
elif ts == 'import':
stmt = self.parse_import()
elif ts == 'from':
stmt = self.parse_import_from()
elif ts == 'class':
stmt = self.parse_class_def()
is_simple = False
elif ts == 'global':
stmt = self.parse_global_decl()
elif ts == 'nonlocal' and self.pyversion >= 3:
stmt = self.parse_nonlocal_decl()
elif ts == 'assert':
stmt = self.parse_assert_stmt()
elif ts == 'yield':
stmt = self.parse_yield_stmt()
elif ts == 'del':
stmt = self.parse_del_stmt()
elif ts == 'with':
stmt = self.parse_with_stmt()
is_simple = False
elif ts == '@':
stmt = self.parse_decorated_function_or_class()
is_simple = False
elif ts == 'print' and (self.pyversion == 2 and
'print_function' not in self.future_options):
stmt = self.parse_print_stmt()
else:
stmt = self.parse_expression_or_assignment()
import asyncio
from asyncio import Future
@asyncio.coroutine
def compute(x: int, y: int) -> 'Future[int]':
print("Compute %s + %s ..." % (x, y))
yield from asyncio.sleep(0.1)
return x + y # Here the int is wrapped in Future[int]
@asyncio.coroutine
def print_sum(x: int, y: int) -> 'Future[None]':
result = 0 # type: int
result = yield from compute(x, y)
from typing import Undefined
a, b, c = Undefined, Undefined, Undefined # type: (A, B, C)
c = a + c # Fail
a = a + b # Fail
c = b + a # Fail
c = a + b
class A:
def __add__(self, x: 'B') -> 'C':
pass
class B:
pass
class C:
pass
from typing import TypeVar, Generic, Undefined, List
T = TypeVar('T')
class Container(Generic[T]):
def __init__(self) -> None:
pass
class A:
pass
class B(A):
pass
ca = Undefined # type: List[Container[A]]
cb = Undefined # type: List[Container[B]]
ab = Container() # type: Container[B]
ba = Container() # type: Container[A]
ca.append(ab)
cb.append(ab) # Fail
cb.append(ba) # Fail
... I also think that this particular tool may be able to help Dropbox convert our own Python 2-based codebase to Python 3.
Guido Van R., Dropbox engineer
Thank goodness we don't have only serious problems, but ridiculous ones as well.