I want to discuss one feature for handful working with shapes of array-like objects. If we want to pass arrays to function we can declare their sizes directly with argument declaration:
``` def foo(a[m, n], b[n]): for i in range(m): for j in range(n): a[i, j] = b[j] ```
Will be equivalent to
``` def foo(a, b): m, n = a.__shape__() n_b = b.__shape__() if n_b != n: raise ShapeNotValidException() ... ```
Objects should implement `__shape__` magic method to use this syntax. Shapes automatically introduced to variables and checked.
Also we can allow more complex checks, e.g.:
``` def bar(a[2,...]): ... ``` will check that first dimension of passed array equals to 2.
Or: ``` def bar(a[n], b[2*n]): # checks that a.__shape__() == 2 * b.__shape__() ... ```