Statically type a subset of Python 3
Nope is a statically-typed subset of Python 3 that can be compiled to multiple targets. At the moment, only Python and node.js are supported. Any valid Nope program can be run directly as a Python 3 program.
Static typing is supported for two main reasons:
The static types are expressed using comments, rather than annotations, for several reasons:
Here’s an example of calculating Fibonacci numbers using Nope:
#:: int -> int def fib(n): seq = [0, 1] for i in range(2, n + 1): seq.append(seq[i - 1] + seq[i - 2]) return seq[n] print(fib(10))
This section describes support for parsing and type-checking each of Python 3.4’s syntax nodes. Note that not all backends may support all features.
Function definitions: partially supported.
The signature of a function should be specified by a signature comment immediately before the function definition. For instance:
#:: int -> int def increment(x): return x + 1 #:: int, str -> none def repeated_greeting(repeat, message): for i in range(0, repeat): print(message) #:: repeat: int, message: str -> none def repeated_greeting(repeat, message): for i in range(0, repeat): print(message)
Class definitions: unsupported.
Return statements: supported.
Delete statements: unsupported.
Assignments: partially supported. Assignments to variables (e.g. x), elements of sequences (e.g. x[i]), and attributes (e.g. x.y) are supported, but not assignment to slices (e.g. x[:]).
Augmented assignments: unsupported.
For loops: supported.
While loops: supported.
If statements: supported.
With statements: supported.
Raise statements: partially supported. Only statements in the form raise value are supported. raise, raise ExceptionType and raise value1 from value2 are unsupported.
Try statements: partially supported. Tuples of exceptions are not supported when specifying the type in exception handlers. The else branch is ignored.
Assert statements: supported.
Import statements: partially supported. The various forms of import statement are supported. However, only local modules are currently supported. Modules from the standard library or dependencies are unsupported.
global keyword: unsupported.
nonlocal keyword: unsupported.
Expression statements: supported.
pass keyword: supported.
break keyword: supported.
continue keyword: supported.
Consider the following:
with x: y = f() g(y)
It isn’t guaranteed that y has been assigned a value since f() could raise an exception that is then suppressed by the context manager’s __exit__ method. Therefore, g(y) fails to type-check. (If the exception isn’t suppressed by the __exit__ method, we can safely assume treat the variable as assigned since we won’t be executing any code after the exception). However, in the common case, we’d like to be able to assume that the variable has been assigned, and such an assumption is safe in many cases, such as:
with open(path) as file_: contents = file_.read() print(contents)
We can allow such examples to type-check by inspecting the type of __exit__. If its return type is none, then it is guaranteed to return a false value, meaning it will never suppress exceptions.
Any valid Nope program should be directly executable using Python 3.4. The best way to support earlier versions of Python is in the same way as you would on a normal Python 3.4 codebase i.e. avoiding features unsupported in earlier versions.
Supported builtin functions:
Nope does not allow subclassing of some builtins, such as int and list. This restraint means a value of type int is guaranteed to have the concrete type int rather than a subclass of int, allowing certain optimisations to be used when generating code.