Fuzion Logo
flang.dev — The Fuzion Language Portal
JavaScript seems to be disabled. Functionality is limited.

Parentheses

Parentheses typically have three purposes in programming languages:

Parentheses in Operator Expression

Parentheses for Operator Precedence

Just as one would expect, parentheses in Fuzion can override default operator precedence in Fuzion. This can be particularly important since operators could be prefix, infix, or postfix operators:

  f (s string) is
    prefix  +       => f("<" + s + ">")
    postfix +       => f("[" + s + "]")
    infix   + (g f) => f("(" + s + "," + g.s + ")")
    redef asString => s.asString

  say "(1): " + (+ f("a") + + + f("b") +)
  say "(2): " + ((+ f("a")) + ((+ (+ (f("b") +)))))
  say "(3): " + ((+ ((f("a") +) +) + f("b")) +)

Here, the expression passed to say marked with (1) will produce the same output as the one marked with (2), while the parentheses used in (3) results in completely different output:

(1): (<a>,<<[b]>>)
(2): (<a>,<<[b]>>)
(3): [(<[[a]]>,b)]

Parentheses for Multi-line Expressions

Expressions in Fuzion are restricted to a single code line. For expressions to be able to extend over several source code lines, they must be enclosed in parentheses:

  x := 1 + 2 + 3 + 4 + 5 +
       6 + 7 + 8 + 9 + 10

Will cause a compile time exception since this will be parsed as two statements, first

  x := 1 + 2 + 3 + 4 + 5 +

followed by

       6 + 7 + 8 + 9 + 10

Resulting in two errors: First, the second lines indentation is invalid, and also thare is no postfix + operator that could be applied to 5 at the end of the first line.

To compile these two lines, we can use parentheses as follows:

  x := (1 + 2 + 3 + 4 + 5 +
        6 + 7 + 8 + 9 + 10)

Parentheses in Calls

Function call chaining

Parentheses in calls are optional in Fuzion as long as the innermost call takes the last argument, e.g,, the calls in

  f(x, g(h(y, z)))

Are equivalent to

  f x, g h y, z

However, if an inner call takes only part of the following argument such as the call to h in

  f(x, g(h(y)), z)

requires parentheses as follows

  f x, g h(y), z

For the parser to distinguish this from the previous code.

Function calls and operators

Mixing operators, in particular prefix operators with calls causes problems for the parser if parentheses are left out. In this code:

  a := f(-x)

Leaving out the parentheses results in

  a := f -x

Which can be parsed as an infix minus operator applied to f and x. So we need to put parentheses in a call if the first parameter starts with a prefix operator, which is somewhat ugly.

Alternatively, we can change the parser to syntactically differentiate infix and prefix operators as follows, similar to what is done in XL: An operator with white space (including comments) to its left and no white space (nor comments) to its right would be parsed as an infix operator. Consequently, the following code would all compile as a call to f with argument -x:

  # all of the following lines will call f with argument -x
  a := f(-x)
  a := f(- x)
  a := f( - x)
  a := f -x
  a := f /* first and only argument: */ -x
  a := f/* first and only argument: */-x

While the following code would be parsed as infix - applied to f and x:

  # all of the following lines will call the infix operator '-' as in f.infix -(x)
  a := f-x
  a := f - x
  a := f- x
  a := f-/* <- this is an infix minus */x

Using white space to change the semantics of a program causes a lot of dispute. However, if you look at these examples, interpreting the white space as suggested here results in the least surprise for human readers, so the danger of introducing errors can be expected to be very low.

There are other situations where white space would change the semantics as well, examples are the differences between x ++ y and x + + , where the first uses an infix operator ++ and the second uses two operators, a postfix + and an infix +. Similarly, foobar is clearly sementically different from foo bar.

Parentheses in Feature Declarations

TBW

Parentheses for tuples

TBW