RussBaz / enforce

Python 3.5+ runtime type checking for integration testing and data validation
542 stars 21 forks source link

Some notes on runtime type safety of Generics #11

Closed RussBaz closed 8 years ago

RussBaz commented 8 years ago

Generics and Type Variables

Some Definitions

A 'Generic' is any mutable object which is a subclass of typing.Generic.

Parametrised Generic is a Generic which accepts one or more type parameters. These parameters must be instances of typing.TypeVar.

Restricted Generic is a Parametrised Generic class that specifies which types it accepts and at least one of the required types must be more specific than typing.Any.

Typed Generic is a Generic which has runtime type checking applied to it.

Type Safe Method/Function is any method/function with a runtime type checking applied to it.

A Proxy object is an object which wraps another mutable object and proxies all its attribute accesses to the wrapped object. If a proxy was defined with an attribute named identically to the wrapped one, then the proxy attribute will be accessed instead. In all other cases it should mimic the wrapped object as much as possible.

A Generic Proxy is a proxy object for a type safe access to the type un-safe Generic.

Safe Generic is either an instance of a typed generic or a generic proxy.

Enforcing generic type safety means ensuring that only safe generics are acceptable. If any non-typed restricted generics are encountered, then they must be silently wrapped in a generic proxy.

Methods, lambdas and functions can be collectively called callables.

Type Safe Callables (or just safe callables) are callables with a runtime type checking applied.

Basic Rules of Type Safety and Generics

Only callables can have a type safety checking.

If a safe callable expects a restricted generic anywhere in its input, then a generic type safety must be enforced on such input.

If a safe callable expects to return a restricted generic anywhere in its output data, then it also must enforce a generic type safety on its output.

TypeVars are invariant by default (PEP 484).

Parameters of Generics are always TypeVars (PEP 484).

Immutable types must always be treated invariantly.

TypeVars can be covariant, contravariant, both or neither (PEP 484).

Mutable types are covariant unless they are parametrised generics.

Parametrised generics are evaluated against their own type invariantly and against their type parameters according to their definition.

TheDataLeek commented 8 years ago

Should/could we have a wiki to lay down these sort of notes/rules on expected behavior? Then we can make issues if there's something wrong with it.

RussBaz commented 8 years ago

Added an entry in the Wiki instead: https://github.com/RussBaz/enforce/wiki/Notes-on-runtime-type-safety-of-Generics.

Closing this issue then.