Scope
A scope is akin to a dictionary, where values are associated with keys.
Definition
Scopes are defined using curly brackets {}
, as shown below:
myCoolScope = {
place = 'here'
when = 'now'
}
Scopes store entries in alphabetical order, a characteristic that becomes apparent when mapping over a scope.
Access
There are three ways you can directly access entries inside a scope.
Dot syntax
myCoolScope.place # output: 'here'
Get syntax
# assuming prop = 'place'
myCoolScope(prop) # output: 'here'
In both methods, if the property is not present, null
is returned. If the outer scope is not found, an error is raised.
Optional chaining syntax
Use the question-dot ?.
operator to safely chain potentially non-existent outer scopes:
nonExisting?.prop # returns null
The optional chaining syntax does not raise an error when the outer scope is null
.
Operations
==
equal!=
not equal+
addition (merge effect)-
subtraction (difference effect)&
logical AND|
logical OR
logical AND/OR evaluate empty scopes as
false
, otherwisetrue
Scope addition (merge)
The second operand acts as a patch for the first operand:
x = { a = 1, b = 3 }
y = { b = 2 }
x + y # results in { a = 1, b = 2 }
y + x # results in { a = 1, b = 3 }
values from the second operand replace those from the first
Scope subtraction (difference)
Subtraction removes elements from the first operand that are identical to those in the second operand:
x = { a = 1, b = 3 }
y = { a = 1 }
x - y # results in { b = 3 }
only values that are exactly identical are removed
Scoped Blocks
Scoped Blocks in FatScript allow for executing statements within the context of a specific scope:
object.{
# Statements executed in the context of 'object'
}
Here, object
is the target scope. Within the block, you can directly access and modify object
's properties.
Features
- Isolation: entries declared within a Scoped Block are local to that scope and do not affect the outer scope
- Outer Scope Access: Scoped Blocks can access entries from the outer scope
Example
x = {}
x.{
a = 5 # 'a' is now a property of 'x'
b = a + 3 # 'b' is also a property of 'x'
}
Scope interactions
FatScript uses sophisticated mechanisms for managing variables across different scopes, leveraging concepts of lexical scoping and shadowing to provide powerful programming capabilities. This section explores these mechanisms, including assignment nuances, increment/decrement behaviors, and the innovative use of the +=
operator for boolean toggling.
Assignment
The assignment operator (=) copies values from outer scopes into current scope, defining a new value:
~ n = 1
x = {}
x.{ ~ n = n } # now x.n == 1, and x.n is independent from root.n
x.{ c = n } # has similar effect, however 'c' is immutable
the same concept applies to code running on a method scope
Caveat
Using ~ n = n + 1
inside a block or method adds a new 'n' in the current scope, initialized with the value of n + 1
from the nearest enclosing scope, without altering the outer n
.
Incrementing and decrementing
Increment (+=) and decrement (-=) operations, interact with variable scoping in a different way. These operations search for the nearest instance of a variable, starting from the current scope and moving outward recursively, and then modify that instance directly.
~ outerN = 1
fn = -> {
outerN += 1 # targets and increments 'outerN' in the outer scope
}
Auto-initialization with +=
FatScript also provides a special behavior regarding increment operator (+=). If the entry doesn't exist, increment works as a regular assignment as if you had written the following for n += 1
:
n == Void ? n = 1 : n += 1
The auto-initialization feature can be particularly useful when used in combination with dynamic entries for dynamic programming.
this feature is exclusively available for increment operator, decrement can't initialize non-existent values
Boolean toggling with +=
Generally, booleans don't allow addition operations. FatScript, however, extends the +=
operator's functionality to boolean types, allowing for an intuitive toggle mechanism within inner scopes.
The expression flag += !flag
effectively toggles the boolean value, even when flag
is defined in an outer scope.
in the particular case of booleans, the only distinction between
=
and+=
is scoping
Other compound assignment operators
Similarly, other compound assignment operations such as *=
, /=
, %=
, and **=
are supported by numeric types and respect the same scoping rules that apply to increment and decrement operations.