In Field you author code inside the properties of Visual Elements (aka "boxes") — how does Python's scoping and namespace rules map onto these boxes?
Quite simply: the contents of visual elements are all in the same namespace — boxes and their properties are not modules. What's global to a visual element is global to everything in the entire sheet, and indeed, all other sheets.
This is a clear sacrifice of scalability (the help that the language gives you for making complex things) for speed, and clearly, there is a whole class of bugs where global variables from boxes accidently tread on each other during runtime. That said, the current thinking (at least by Marc) is that this is the correct tradeoff. A few points in its defense:
_self
and propertiesThis is the most important one. Things that need to be local to a box can simply be stored in _self
. This is strictly more powerful than any visual-element-as-module solution, since _self
delegates upwards through the delegation graph. Note: if you are storing things that cannot be persisted (in particular Python functions and other complex Python objects), remember to use non-persistent properties — anything with a trailing underscore '_'.
Also, you should note that _self.something_
returns None
should something_
be missing, not a thrown NameError
. This allows the common pattern:
_self.something_ = _self.something_ or expensiveToConstruct()
Alternatively, you could put your bindings to _self.something_
into the python_autoExec_v
property, and have them set at startup.
Finally, remember that you can always get hold of some other element's "_self" and ask it for variables:
print _self.find["some other element"].something_
#prints the something_ of the element called "some other element"
#or
print marked()[0].something_
#prints the something_ of the first marked element (you mark things by pressing ⌘-left-click)
This means that boxes may be used to make a kind of Field "module", although you should note that _self
is dynamically, not lexically, bound: _self
will evaluate to the box that's doing the calling, not the box where _self
is written. If you really want to refer to a specific, unchanging, non-dynamically dispatched visual element, look it up by name and / or store it in a global variable.
Emphasizing this module-like nature of visual elements is the convenience shorthand: _someElement()
— _self
like variables are callable, and calling them executes the code from top to bottom. (See also _self.begin()
and _self.end()
).
Global variables and global definitions have the same scoping rules (in Field and in Python). Global-izing definitions makes making libraries of shared functions and classes fast, loose and organic. Often some visual elements end up with carefully cleaned up function and class definitions, and a handful of important instances, while other elements are a rag-tag bunch of scratch code-in-progress.
To emphasize and support this use of the global namespace, Field does something very unexpected (but useful) — it automatically executes elements needed to resolve global definitions (and variables). If I have a visual element 'A' that is known to def foo():
, or set bar=10
and I have some other box 'B' that says foo()
or print bar
then just before that NameError
would get thrown, element 'A' is executed in its entirety.
This seems dangerous — and it can be. But in general it has been found to be incredibly useful. A general usage pattern with Field: execute some code, execute some more code, write some code and eventually you get to the point where you need to change some Java. Eclipse comes out, the change is made, you restart Field. Now you need to get back to where you were before as fast as possible, this delay directly effects how much work you can get done in a day. The execution ruler (see TextEditor) and it's red breadcrumb trace is one part of that, but this autoexecution is another.
You can browse the interdependancies between elements by selecting the search axis "offers global variables" from the selection window (or un-pausing the logging window):
Alternatively you can highlight a symbol and right click on it in the text editor:
Selecting that menu item will take you to where that symbol was defined.
Sometimes while building something up you fall into the trap of using global variables (because it's quicker to type) and then regret it — you wish that you'd made all of those foo
s _self.foo_
instead. Enter makeBoxLocalEverywhere
:
makeBoxLocalEverywhere("foo")
This is a very powerful command. After this code has been executed global access to foo
is just like writing _self.foo_
. Now you can build up delegation heirarchies around boxes &mdash refactoring the semantics of your boxes without actually editing any code at all. All those global variables become "box local".