Package: nope
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:Static typing can detect some programming errors more quicklyStatic typing allows optimisations to be applied to the generated codeThe static types are expressed using comments, rather than annotations, for
several reasons:This means the static typing has no effect at runtime, allowing Nope programs
to be run directly as Python 3 programs without any extra dependencies or
performance penalty.A separate syntax can be used within the comments to succinctly express types,
rather than (ab)using existing Python syntax.It can be useful to decouple the signature of a function from the implementation.
For instance, using separate comments makes it easy to type a function such
that it only accepts arguments by positions rather than keyword.Here’s an example of calculating Fibonacci numbers using Nope:#:: int -> intdeffib(n):seq=[0,1]foriinrange(2,n+1):seq.append(seq[i-1]+seq[i-2])returnseq[n]print(fib(10))TODOWhen defining__add__and similar methods on classes,
the type signature should be specific e.g. on int,int->int.
However, to maintain compatibility with Python,
the type checker should assume the argument is the top type when type
checking the actual method, so isinstance or similar still has to be used.Support for the r versions of operators e.g.__radd__.Inheritance__init__methodsStandard library supportA way of specifying dependencies on a per-platform basis to allow shimming
of existing libraries into a common interface.Allow types of variables to be specified in the same way as functions, such
as giving the type of an empty list.If a class definition body contains a value of type object that could
be a function (but that is not possible to determine at runtime), how
should it be treated? In Python, if it’s a function, we bind it to the
instance. Is it possible to sensibly do the same in other languages?
The result is that any value of type object will need to be checked
as to whether it is a function or not for consistency.Proper tests for builtin functionsPrevent re-definition of functions and classesAllow mutually recursive functionsEnsure that all signatures are used in typing rulesStatusSyntaxThis section describes support for parsing and type-checking each ofPython 3.4’s syntax nodes.
Note that not all backends may support all features.Function definitions: partially supported.name: supported.arguments: partially supported.
Positional and keyword arguments are supported, but nothing else
(default values,*args,**kwargs, keyword-only arguments).body: supported.decorators: unsupported.annotations: unsupported (both argument and return annotations).The signature of a function should be specified by a signature comment immediately before the function definition.
For instance:#:: int -> intdefincrement(x):returnx+1#:: int, str -> nonedefrepeated_greeting(repeat,message):foriinrange(0,repeat):print(message)#:: repeat: int, message: str -> nonedefrepeated_greeting(repeat,message):foriinrange(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 formraise valueare supported.raise,raise ExceptionTypeandraise value1 from value2are unsupported.Try statements: partially supported.
Tuples of exceptions are not supported when specifying the type in exception handlers.
Theelsebranch 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.With statementsConsider the following:withx:y=f()g(y)It isn’t guaranteed thatyhas been assigned a value sincef()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:withopen(path)asfile_:contents=file_.read()print(contents)We can allow such examples to type-check by inspecting the type of__exit__.
If its return type isnone, then it is guaranteed to return a false value,
meaning it will never suppress exceptions.PythonAny 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.Node.js backendSupported builtin functions:abs: supportedbool: partially supported. The magic method__bool__is ignored.iter: partially supported. The sequence protocol is unsupported.print: only a single argument is accepted.Unimplemented optimisations:If the result of boolean operations (‘and’ or ‘or’) is only used as a
condition, such as the condition of an ‘if’ statement or ‘while’ loop,
then the value can simply be true or false rather than the actual value
of the operation. In other words,x and ycan be optimised tobool(x) && bool(y).Unlessbool()has been explicitly invoked, booleans, strings and integers
can be used directly if only used for their truth value e.g. in if statement
conditions.Avoid re-evaluating bool(value) if boolean operations are used directly in
conditions. For instance, inif x and y,bool(x)only needs to be
evaluated once, even ifbool(x)isTrue. (A naive implementation
evalutesbool(x)once for theandoperation, which would have the
value ofx, causingbool(x)to be evaluated again as the condition
of theifstatement.)Differences from Python 3Subclassing builtinsNope does not allow subclassing of some builtins,
such asintandlist.
This restraint means a value of typeintis guaranteed to have the concrete typeintrather than a subclass ofint,
allowing certain optimisations to be used when generating code.