-
-
Notifications
You must be signed in to change notification settings - Fork 5
ambiguity
Ambiguity should ideally be resolved by the compiler by asking questions.
a {x=1}
Did you mean a:{x=1} or [a,{x=1}] ?
Consider a b
(a) (b)
{a} (b)
and {a}(b)
.
Are they the same? A group with one element is identical to the element itself:
Axiom (a) == a
Is a block with one element identical to the element itself?
{a} == a ?
Is {a} (b)
a list with elements {a} and b or is it b applied to {a} {a}(b)
?
square 3
yields a certain beauty
However when mixing function calls and operators, things can get ambiguous quickly:
square 3 * 3
can be read as square (3 * 3)
or (square 3) * 3
square 3 + square 3
can be read as square (3 + square 3)
or (square 3) + square 3
One way to resolve ambiguities us by inserting braces
square 3 + 4 times 3
square(3 + (4 times 3))
Even though there might not be an ambiguity to the compiler, it can be helpful to insert braces to make it easier for the user to parse the meaning:
a or b and c => a or (b and c)
The reasoning behind this is that the developer might not always we be aware of the function operator precedence.
while (char c = dest[i] and i>0)
sets c to 0 or 1 because and binds stronger than assignment!!
In lambda expressions, the it
keyword refers to the first (implicit argument), otherwise it refers to self or the last result, which can be very ambivalent:
double=it*2 # ok, [evaluate](evaluation) immediately?
double:it*2 # may evaluate to anything later
double:=it*2 # ok, implicit argument for function 'double'
map [1 2 3] square
could be read as
map [1 2 3] :square
symbolic function pointer
map ([1 2 3] square) == map [1 4 9]
The last interpretation makes no sense just be sure to test that it never happens
ambiguous assignment concepts:
name, age, source = "Crystal, 123, GitHub".split(", ") # deconstruction assignment
name age, source := "Crystal, 123, GitHub".split(", ") # function 'name' with arguments age, source
The last case is especially problematic with
name age := age+1 The function 'name' with parameter age could also be read as name_age or age(type=name)
Ideally we could reconcile f={a:1 b:2} f[a] == 1
with the current mechanism f(a=3) == {a:3 b:2}
or f(a=3) == b:2
or f(a=3)==2
because the last expression of the block is returned.
Map matching versus block selection versus construction.