Calls
Parentheses in calls are optional. How about commas to separate actual
arguments and dots to separate the call target from the called feature name?
Other Languages
Haskell call syntax
Haskell omits parentheses and commas in function calls, i.e.
a b c d
is equivalent to the Java code a(b,c,d)
. Further examples, inspired by schoolofhaskell.com :
Haskell |
Java |
Comment |
a b c d |
a(b,c,d) |
|
f -1 |
f-1 |
CAVEAT: This is not a call, but an infix operation! |
f (-1) |
f(-1) |
Parentheses around argument make this a call. |
(f a b) |
f(a,b) |
Parentheses go around a call |
a b * c d |
a(b)*c(d) |
Call has highest precedence |
a (b * c) d |
a(b*c, d) |
Parentheses are needed around infix/prefix/postfix expressions given as call arguments |
f g x |
f(g, x) |
Even if f, g are both functions, g is not called here, but passed as
argument to f. Function call binds to the left. |
f (g x) |
f(g(x)) |
Parentheses are required to pass the result of applying g to x to f . |
f $ g $ x |
f(g(x)) |
Alternatively, $ can be used as a function call operator that binds to the right. |
(f . g) x |
int fg(int y) { return f(g(y)); }
fg(x); |
Function composition in Haskell is done using a dot. |
f x y = x + y*y
g = f 3
g 4 |
int f(int x, y) { return x + y*y; }
int g(int y) { return f(3, y); }
g(4); |
Currying: Applying only a part of the arguments to a function results
in a function that expects the remaining arguments. |
f (a, b) |
record Tuple(int v, int w) { }
f(new Tuple(a, b)) |
Classical call syntax in Haskell with comma-separated arguments results in a call with one argument that is a tuple. |
Scala-3
The following table contains examples inspired by a discussion on stackoverflow.
TBD: What does call syntax in Scala-3 look like? Any changes?
Scala |
Java |
Comment |
o.m(a) |
o.m(a) |
Dot notation like in Java. |
o m (a) |
o.m(a) |
Operator notation. |
o m a |
o.m(a) |
Operator notation with single argument does not require parentheses. |
o m |
o.m() |
Operator notation without arguments does not require parentheses. |
a m: o |
o.m:(a) |
Operator notation inverts target and arguments if called method ends in : . |
Nim
Examples inspired by manual
at nim-lang.org.
Nim |
Java |
Comment |
m(o, a) |
o.m(a) |
Not object-oriented style notation. |
o.m(a) |
o.m(a) |
Dot notation like in Java. |
o.m |
o.m() |
Parentheses are optional for dot notation with no arguments |
Fuzion call syntax
The following tables show what is currently considered for Fuzion:
Call with and without parentheses
Fuzion |
Haskell |
Java |
Comment |
a(b,c,d) |
a b c d |
a(b,c,d) |
Fuzion should support classic call syntax. |
a b c d |
a b c d |
a(b,c,d) |
Parentheses and commas should be optional. |
a b (c d) |
a b (c d) |
a(b,c(d)) |
Parentheses group calls and arguments. |
a (b c) d |
a (b c) d |
a(b(c),d) |
Parentheses group calls and arguments. |
Examples
Binding strength of calls and prefix/postfix operators:
Fuzion |
Haskell |
Java |
Comment |
f -1 |
f (-1) |
f(-1) |
Raku-style: infix or postfix operators bind stronger if there is no
space between the operator and its operand. |
f - 1 |
f - 1 |
f - 1 |
With spaces, we get an infix operator, so this is equivalent to f.infix -(1) . |
f-1 |
f - 1 |
f - 1 |
Without any spaces, we also get an infix operator, so this is equivalent to f.infix -(1) . |
f x-1 |
f (x-1) |
f(x-1) |
Extended Raku-style: infix operators without space bind stronger than calls! |
f x - 1 |
f x - 1 |
f(x) - 1 |
Extended Raku-style: infix operators with space bind weaker than calls! |
f x -1 |
f x (-1) |
f(x, -1) |
Raku-style: prefix operators without space bind stronger than calls! |
f x- 1 |
f (x-) 1 |
f(x.postFixMinus(), 1) |
Raku-style: postfix operators without space bind stronger than
calls, so this is equivalent to f(x.postfix -, 1) . |
Examples
Calls with parentheses:
Fuzion |
Haskell |
Java |
Comment |
f(a b c) |
f (a b c) |
f(a(b, c)) |
Parentheses may go around all arguments and commas can be omitted, turning this into f(a(b, c)) . |
f(a, b, c) |
(f a b c) |
f(a, b, c) |
Parentheses may go around all arguments, requiring commas to avoid
turning argument list into a call. So this is equivalent to f a b
c . |
(f a b c) |
(f a b c) |
f(a,b,c) |
Parentheses may go around a call |
Examples
Binding strength of calls and infix operators:
Fuzion |
Haskell |
Java |
Comment |
a b * c d |
a b * c d |
a(b)*c(d) |
Call has highest precedence, so this is equivalent to a(b) * c(d) . |
a b*c d |
a (b * c) d |
a(b*c, d) |
infix operator without spaces has higher precedence than call. so this
is equivalent to a(b*c,d) . |
Examples
Function Composition
Fuzion |
Haskell |
Java |
Comment |
f g x |
f g x |
f(g, x) |
Even if f, g are both functions, g is not called here, but passed as
argument to f. Function call binds to the left. |
f(g x) |
f (g x) |
f(g(x)) |
Parentheses are required to pass the result of applying g to x to f . |
NYI: Compose operator |
(f . g) x) |
int fg(int y) { return f(g(y)); }
fg(x); |
Function composition via a dedicated operator is currently not
supported. Need compelling use cases to justify this, could be realized
with syntactic sugar. |
Examples
Currying
Fuzion |
Haskell |
Java |
Comment |
f(i32 x, y) => x + y*y
g => f 3 # NYI! Currying
g 4
|
f x y = x + y*y
g = f 3
g 4 |
int f(int x, y) { return x + y*y; }
int g(int y) { return f(3, y); }
g(4); |
NYI: Currying: Applying only a part of the arguments to a function results
in a function that expects the remaining arguments. |
Examples
Tuples as arguments
Fuzion |
Haskell |
Java |
Comment |
f((a, b)) |
f (a, b) |
record Tuple(int v, int w) { }
f(new Tuple(a, b)) |
Passing a tuple in Fuzion requires double-parentheses to disambiguate
passing a tuple from a call using parentheses. |
f (a, b) |
f (a, b) |
record Tuple(int v, int w) { }
f(new Tuple(a, b)) |
Separating the argument from the name of the called feature turns the
argument into a tuple. |
Examples
Object-oriented style calls
Fuzion |
Haskell |
Java |
Comment |
obj.m x |
-- |
obj.m(x) |
Object-oriented dot notation for a call. Here, the scope to
lookup m is different, m is searched for in the visible
features of the static type of obj only. |
obj m x # not supported! useful? |
-- |
obj.m(x) |
Scala-like operator notation for a call. This would result in an
ambiguity if m exists both in the local scope and in the static
type of obj . Which m should be taken in this case? |
m obj x # not supported! useful? |
-- |
obj.m(x) |
Nim-style call syntax for object-oriented calls. If f64
declares sin , this would permit code like sin α for
a f64 value α instead of α.sin . Does this justify
extending the call syntax? An alternative with the same effect would be
to declare sin within a different unit-type feature trigo
and then either use trigo.sin α or to inherit trigo to
make sin visible such that a call sin α is possible. |
Examples
Type parameters
Fuzion |
Haskell |
Java |
Comment |
myMap i32 String |
myMap i32 String |
myMap<i32,String>() |
Fuzion syntax for type parameters in a call is the same as
for value parameters, i.e., using either spaces
or ( , ) to separate
arguments. |
myMap(i32, String) |
myMap i32 String |
myMap<i32,String>() |
Examples
Dollar / left pipe / apply-to operator in calls
Haskell provides the $
operator, F# has <|
to avoid parentheses in chained calls. Do we need this in Fuzion?
Fuzion |
Haskell |
F# |
Comment |
draw (point (a (b x) (a (b y)))) |
draw $ point (a $ b x) (a $ b y) |
draw <| point (a <| b x) (a <| b y) |
Which of these is best? |
last changed: 2024-06-28