-
-
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}] ?
a>b:c
Did you mean a>b : c
or a > b:c
?
significant whitespace / semantic resolution
in general in wasp lists plus element means extending the list:
(x,y)+z=(x,y,z)
in general in wasp lists of one element are identical to the element:
(x)=x
however this might lead to conflicts, eg in list extensions:
(x)+y=(x y) ≠ x+y
resolvable by the parser?
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)
?
while the precedence of ',' and '; is clear:
1,2;3,4 == ((1,2);(3,4)) the precedence of ',' and ' ' less is clear:
1 2 3 , 4 5 6and
1,2,3 4,5,6`
both seam like reasonably natural groupings.
For colons the situation is dire as well:
a b c:d
versus
to skin a cat: do something
significant-white space to the rescue!
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
Operators bind more tightly than functions. Only the last case where functions are inter-mixed needs special attention:
One way to resolve ambiguities is by making the IDE suggest and insert 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 expression, 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, [interpret](evaluation) immediately?
double:it*2 # may interpret 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]
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.
a is not b // ambiguity: a == !b vs a != b