All variables in Libretto are local and inaccessible from the global context. The types of Libretto variables are:
Unlike block and path variables, parameter variabels can be explicitly typed. Such typing is a key for polymorphic definitions:
Like in functions, constructor parameters (both fields and variables) can also have default values, for instance:
In case of ambiguity, when the names of a variable and another entity coincide, the name is always interpreted as the variable:
- Block variables
- Path variables
- Parameter variables.
var
) and immutable (marked by fix
).
- Block Variables
- Path Variables
- Variable Typing
- Mutable and Immutable Variables
- Variable Initialization
- Parameter Passing in Constructors and Functions
- Access to Local Variables
Block Variables
Block variables are defined in blocks, for instance, in the body of a function:def* size { var x = 0 this. {x = x + 1} x }Here
x
is a block variable defined in the body of the function size
. The scope of x
is limited by the curly brackets of the function body.
Path Variables
The range of local variables introduced by the operatorsas
and index
is the path, in which they are defined, and its sub-paths:
(“a”, “b”) as s. (1,2) as n. (a + n) // “a1” “a2” “b1” “b2”The range of the variables
s
and n
is from the step, in which they are introduced, to the rightmost step of the path.
Variable Typing
The block and path variables are type-free. A block variable can be marked by the asterisk*
, which means that this variable is able to contain a sequence of values:
{ var seq* = 2 seq .= “Marie has” seq += “candies” seq // “Marie has” 2 “candies” seq.size // 3 var single = (1,2) // ERROR: too many values in variable single }The variable
seq
can contain an arbitrary number of values, whereas single
can have only zero or one value.
Unlike block and path variables, parameter variabels can be explicitly typed. Such typing is a key for polymorphic definitions:
def f(x: Int) = x * x def f(s: String) = s + s f(5) // 25 f(“abc”) // “abcabc” { fix x = 5 fix y = “abc” f(x) // 25 f(y) // “abcabc” }The block variables
x
and y
are type-free, but dynamic dispatch manages to find the appropriate definition of the function f
, because it is based on the actual types of values stored in variables.
Mutable and Immutable Variables
Variables in Libretto are divided into immutable and mutable variables. The first ones are marked by the keywordfix
, and the second – by the keyword var
:
{ var x = 1 fix y = 1 x = 2 x // 2 y = 1 // ERROR: the attempt to reassign fix variable y }Path variables are always immutable, they can not be explicitly modified:
(“a”, “b”) as s. {s = 5} // ERROR: attempt to reassign fix variable sA sequence in Libretto is not a compound data structure, but a generalized single value. This means that unlike, say, lists (see section Class List) the modification of a sequence is considered as the modification of the variable, which contains this sequence. In particular, sequences in immutable variables can not be modified:
{ fix xf* = (1,2,3) xf += 4 // ERROR: attempt to reassign fix variable x }If we need to change a sequence, it has to be copied into a mutable variable:
{ fix xf* = (1,2,3) var xv* = xf xv += 4 xv // 1 2 3 4 }Using immutable variables where possible is a good programming style, which provides better-quality code development with a reduced number of bugs.
Variable Initialization
For each kind of variables there is a special initialization method. For block variables an assignment operator is used:{ var x = 115 fix name = “Marie” }If a block variable is not initialized explicitly, it is set by default as
()
:
{ var x if (x) “yes” else “no” } // “no”Path variables are initialized by the operators
as
and index
:
(1,2,3) as x. (5 + x) // 6 7 8 (“a”, “b”, “c”) index i. i // 0 1 2Parameter variables are initialized in function calls:
def f(x) = x + 1 f(3) // 4
Parameter Passing in Constructors and Functions
Function parameters are always private immutable variables. They are inaccessible from outside, and their value can not be modified:def f(n*) { n += 6 n } f(1,2,3,4,5) // ERROR: Attempt to reassign fixed variable n def f(n*) { var m = n m += 6 m } f(1,2,3,4,5) // 1 2 3 4 5 6Function parameters can be supplied with default values. If parameters with default values are the rightmost, then they can be omitted in function calls:
def f(n: Int, m: Int = 5) = n + m f(1, 2) // 3 f(1) // 6
Note that inaccurate use of default values in polymorphic definitions can lead to ambiguity and to an error.
Like in functions, constructor parameters (both fields and variables) can also have default values, for instance:
class C(fix prop: String, v: Int = 2) { var n: Int = v var m: Int = v * v } C(“hehe”, 5).m // 25 C(“haha”).m // 4In this example
prop
is a field and v
is a parameter variable. Parameter variables are not marked by var
or fix
. They play a supporting role in object creation. Unlike fields, which are public by default and can be either mutable or immutable, parameter variables in constructors are always treated as private and immutable. The life of a parameter variable is limited to the constructor execution time. After that, this variable is inaccessible.
Access to Local Variables
The range of a local variable in Libretto is always limited to the block or the path, in which the variable is defined. Thus, variables always behave as private.In case of ambiguity, when the names of a variable and another entity coincide, the name is always interpreted as the variable:
object obj extends String(“c”) class C { fix field = “ab” def f1 = field + obj def f2 = {fix field = 5; fix obj = 6; field + obj} } C().f1 // “abc” C().f2 // 11If the other entity must be accessed, the operators
%
and @
are used (see sections Operator @
and Parametric Fields and Operator %
). The operator %
interpets its argument as an object, and @
interprets its argument as a field:
object obj extends String(“c”) class C { fix field = “ab” def f1 = field + obj def f2 = {fix field = 5; fix obj = 10; @field + %obj} } C().f1 // “abc” C().f2 // “abc”
No comments:
Post a Comment