MEP | Title | Discussion | Implementation |
---|---|---|---|
2 |
Local Variables |
XXX |
This MEP proposes syntax and semantics for variables that are local to a cell.
Variables declared with a single leading underscore, such as _x
or _
(but not starting
two underscores] __
) are not added to a cell's list of definitions, and are unavailable to other cells.
The rule against declaring the same global name in multiple cells can be unwieldy, since some names may be declared at a cell's top-level scope but meant only to be used within the cell as an internal or private variable.
Underscore.
An important example is the underscore identifier _
, used to communicate that
a value is unused: e.g.,
_, value = f()
Loop variables. Another important example class are loop variables:
for i in range(10):
...
Because scoping in Python is leaky, i
becomes a global variable, even
though in most cases the programmer won't ever read i
after the loop body.
This same problem arises in with
statements.
Temporaries. A name may be used to bind to a temporary or intermediate value in a computation to minimize redundant computation or for legibility of the code:
b = X @ a
c = Y @ b
d = Z @ b
Here, perhaps c
and d
will be used by other cells, but b
won't.
Any name that begins with an underscore is treated as a local variable.
Examples:
Unpacking.
_, value = f()
Here _
starts with an underscore, so it is a local variable.
Loop variables.
for _i in range(10):
...
Temporaries.
_b = X @ a
c = Y @ _b
d = Z @ _b
Variables prefixed with _
will not be included in the returns of a cell's
defining function.
The syntax follows the familiar idiom of using leading underscores to
designate a variable as private, and it includes the conventional use of _
as
a temporary identifier as a special case.
The syntax makes an exception for names starting with two underscores to prevent
conflicts with system names (like __name__
, __builtins__
, etc) which typically
start with two underscores.
It can be awkward or ugly to prefix variables with underscores. If a programmer finds that they have to do this very often within the same cell, they could instead opt to encapsulate their code within a function (which they may choose to make local), removing the need to prefix the variables.
Sometimes one may actually want a name starting with _
to be available to all cells.
- Imported names may start with
_
. These imported names would need to be aliased to make them available throughout the entire app. - The programmer might want names starting with
_
to be internal to their app, not internal to their cell. In this case, they would need to make internal names start with two underscores instead of one.
Double leading underscore. Treat names with double leading underscores as
private, instead of a single leading underscore. This mitigates the conflict with
traditional naming conventions (with single leading underscore used for internal
to app, instead of internal to cell), but does not allow for using _
as a temporary.
Variable annotation. An alternative to name-based designation of locals is to use a variable annotation, such as
i: mo.local
This may lead to more legible typography, since code will not be cluttered
with underscores. But it is unidiomatic, and does not cover the use of _
as a temporary identifier. Moreover, it leads to ambiguity in the case
that another cell declares i
as a global varible.
No local variables. We could choose to not have any local variables, but
provide a special case for _
. Users would then be very strongly encouraged to
encapsulate code in functions. But they wouldn't be able to make local
functions, pushing the naming problem from variables to functions.
https://github.com/marimo-team/prototype/tree/locals
- Modify the AST visitor to mangle names (ast.Name nodes, and identifier strings)