Access
There are four access expresions:
- namespace member access
- routine member access
- container memeber access
- field member access
Subprogram access
One access form is the receiver-style routine call, often called a “method-call expression” in other languages. In FOL this is still procedural syntax: the receiver value is the first routine input, and dot-call form is just sugar at the call site.
A method call consists of an expression (the receiver) followed by a single dot
., an expression path segment, and a parenthesized expression-list:
"3.14".cast(float).pow(2); // casting a numbered string to float, then rising it to power of 2
Read:
value.method(arg1, arg2)
as the procedural idea:
method(value, arg1, arg2)
The syntax does not introduce classes or object-owned method dispatch by itself.
Namespaces access
Accesing namespaces is done through double colon operator :::
use log: std = {"fmt/log"}; // using the log namespace of fmt
io::console::write_out.echo(); // echoing out
Container access
Array, Vectors, Sequences, Sets
Containers can be indexed by writing a square-bracket-enclosed expression of type int[arch] (the index) after them.
var collection: int = { 5, 4, 8, 3, 9, 0, 1, 2, 7, 6 }
collection[5] // get the 5th element staring from front (this case is 0)
collection[-2] // get the 3th element starting from back (this case is 1)
Containers can be accessed with a specified range too, by using colon within a square-bracket-enclosed:
| syntax | meaning |
|---|---|
: | the whole container |
elA:elB | from element elA to element elB |
:elA | from beginning to element elA |
elA: | from element elA to end |
collection[-0] // last item in the array
{ 6 }
collection[-1:] // last two items in the array
{ 7, 6 }
collection[:-2] // everything except the last two items
{ 5, 4, 8, 3, 9, 0, 1, 2 }
If we use double colon within a square-bracket-enclosed then the collection is inversed:
| syntax | meaning |
|---|---|
:: | the whole container in reverse |
elA::elB | from element elA to element elB in reverse |
::elA | from beginning to element elA in reverse |
elA:: | from element elA to end in reverse |
collection[::] // all items in the array, reversed
{ 6, 7, 2, 1, 0, 9, 3, 8, 4, 5 }
collection[2::] // the first two items, reversed
{ 4, 5 }
collection[-2::] // the last two items, reversed
{ 6, 7 }
collection[::-3] // everything except the last three items, reversed
{ 2, 1, 0, 9, 3, 8, 4, 5 }
Matrixes
Matrixes are 2D+ arrays, thus they have a bit more complex acces way:
var aMat = mat[int, int] = { {1,2,3}, {4,5,6}, {7,8,9} };
nMat[[1][0]] // this will return 4
// first [] accesses the first dimension, then second [] accesses the second
All other operations are the same like arrays.
Maps
Accesing maps is donw by using the key within square-bracket-enclosed:
var someMap: map[str, int] = { {"prolog", 1}, {"lisp", 2}, {"c", 3} }
someMap["lisp"] // will return 2
Axioms
Accesing axioms is more or less like accessing maps, but more verbose and matching through backtracing, and the return is always a vector of elements (empty if no elements are found):
var parent: axi[str, str] = { {"albert","bob"}, {"alice","bob"}, {"bob","carl"}, {"bob","tom"} };
parent["albert",*] // this will return strng vector: {"bob"}
parent["bob",*] // this will return strng vector: {"carl","tom"}
parent[*,_] // this will match to {"albert", "alice", "bob"}
Matching can be with a vector too:
var parent: axi[str, str] = { {"albert","bob"}, {"alice","bob"}, {"bob","carl"}, {"bob","tom"}, {"maggie","bill"} };
var aVec: vec[str] = { "tom", "bob" };
parent[*,aVec] // will match all possible values that have "tom" ot "bob" as second element
// in this case will be a strng vector: {"albert", "alice", "bob"}
a more complex matching:
var class: axi;
class.add({"cs340","spring",{"tue","thur"},{12,13},"john","coor_5"})
class.add({"cs340","winter",{"tue","fri"},{12,13},"mike","coor_5"})
class.add({"cs340",winter,{"wed","fri"},{15,16},"bruce","coor_3"})
class.add({"cs101",winter,{"mon","wed"},{10,12},"james","coor_1"})
class.add({"cs101",spring,{"tue","tue"},{16,18},"tom","coor_1"})
var aClass = "cs340"
class[aClass,_,[_,"fri"],_,*,_] // this will return string vector: {"mike", bruce}
// it matches everything that has aClass ad "fri" within
// and ignore ones with meh symbol
Avaliability
To check if an element exists, we add : before accessing with []. Thus this will return true if element exists.
var val: vec = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
val:[5] // returns true
val:[15] // returns false
var likes: axi[str, str] = { {"bob","alice"} , {"alice","bob"}, {"dan","sally"} };
likes["bob","alice"]: // will return true
likes["sally","dan"]: // will return false
In-Place assignment
One of the features that is very important in arrays is that they can assign variables immediately:
var val: vec = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
var even: vec = {2, 4, 6, 8, 10, 12, 14, 16, 18, 20}
val[even => Y] // this equals to {2, 4, 6, 8, 10} and same time assign to Y
.echo(Y) // will print {2, 4, 6, 8, 10}
This dows not look very much interesting here, you can just as easy assign the whole filtered array to a variable, but it gets interesting for axioms:
var parent: axi[str, str] = { {"albert","bob"}, {"alice","bob"}, {"bob","carl"}, {"bob","tom"}, {"maggie","bill"} };
parent:[* => Y,"bob"] // this one returns true if we find a parent of "bob"
// same time it assigns parent to a string vector `Y`
Field access
Field access expressoin accesses fields inside constructs. Here is a recorcalled user:
var user1: user = {
email = "someone@example.com",
username = "someusername123",
active = true,
sign_in_count = 1
};
fun (user)getName(): str = { result = self.username; };
There are two types of fields that can be accesed within constructs:
- methods
- data
Methods
Methods are accessed with the same dot form as routine member access, but they remain receiver-qualified routines rather than object-owned behavior.
user1.getName()
Data
There are multiple ways to acces data within the construct. The easiest one is by dot operator .:
user1.email // accessing the field through dot-accesed-memeber
Another way is by using square bracket enclosed by name:
user1[email] // accessing the field through square-bracket-enclosed by name
And lastly, by square bracket enclosed by index:
user1[0] // accessing the field through square-bracket-enclosed by index