_____
---' __\_______
______) Beyond the field - Declarations in Poke
__) structs
__)
---._______)
Jose E. Marchesi
October 23, 2019
The main purpose of Poke structs and unions is to define fields that,
eventually, will be mapped and accessed to inspect and manipulate some
underlying IO space like a file. However, they can also contain
declarations of other entities; namely variables, types and functions.
This is a nice abstraction that allows to implement useful idioms like
setters and getters, pretty printers, and much more. Let's explore
this in some detail.
Lexical Binding and Scoping
Before dealing with struct types, let's first have a super quick look
at how Poke deals with variables. Basically, Poke implements what is
known as "lexical binding". Many programming languages use lexical
binding. Notable examples are Scheme, Pascal and Javascript.
In lexical binding, entities that can be referred by name are
organized in a hierarchical <i>lexical environment</i>. When an
entity is referenced from within a given level in the hierarchy, it is
traversed bottom-up until an entity with the given name is found. If
no entity is found, then an error is produced.
Each level in the lexical environment is introduced by some construct
in the programming language, which always defines a sort of block,
either implicitly of explicitly. For example, compound statements
introduce a new lexical level.
Let's see an example:
{
/* Outer block. */
var a = 10;
var b = "foo";
{
/* Inner block. */
var c = 30;
var a = 2;
printf "a is %i32d\n", a;
}
printf "a is now %i32d\n", a;
In the excerpt above the outer compound statement delimits a block
that introduces it's own lexical level. This block has two
"bindings", associating the name 'a' with an integer variable, and the
name 'b' with a string variable. Similarly, the inner compound
statement introduces another lexical level, with two bindings for 'c'
and 'a'.
When the reference to the name 'a' is found in the inner 'printf', a
search process is performed starting in the current lexical level. In
this case, a binding associating 'a' with an integer variable that
contains the number 2 is found. Therefore, the inner 'printf' prints
2. We say that the inner binding for 'a' "ghosts" the binding of the
same name in the outer block.
When the execution reaches the end of the inner compound statement,
it's associated lexical level is exited: it's bindings are no longer
accessible. Therefore, the searching process triggered by the
reference to 'a' in the outer block results in the variable containing
10, not 2.
Functions also introduce lexical levels, and they can be nested.