Unfinished Ideas

Admittedly, many ideas for Cilia are not yet fully developed, but these really do need some more work.

T^ to Objects of Other Languages

We can redefine T^ for interoperability with other languages, e.g. garbage collected languages like C# and Java.

T^ is defined via type traits SharedPtrType:

T+ is defined via type traits UniquePtrType:

Exotic Operators (e.g. Unicode)

Logical / Bool Operators

It is also possible to use the mathematical symbols , , , , ¬ for and, or, nand, nor, not.

operator (Bool a) ∧ (Bool b) -> Bool { return a and b }
operator (Bool a) ∨ (Bool b) -> Bool { return a or b }
operator (Bool a) ⊼ (Bool b) -> Bool { return a nand b }
operator (Bool a) ⊽ (Bool b) -> Bool { return a nor b }
operator (Bool a) ⊻ (Bool b) -> Bool { return a xor b }
operator ¬(Bool a) -> Bool { return not a }

Vector / Matrix Operators

operator (Vec3 a) × (Vec3 b) -> Vec3       { ... }   // cross product (beware of confusion with the letter 'x')
operator (Vec a) ⋅ (Vec b) -> Float        { ... }   // dot / scalar / inner product

operator (Matrix a) ⊙ (Matrix b) -> Matrix { ... }   // Hadamard (element-wise) product
operator (Matrix a) ⊘ (Matrix b) -> Matrix { ... }   // Hadamard (element-wise) division
operator (Matrix a) ⊞ (Matrix b) -> Matrix { ... }   // element-wise addition ("boxplus")
operator (Matrix a) ⊟ (Matrix b) -> Matrix { ... }   // element-wise subtraction ("boxminus")

operator (Vec a) ⊕ (Vec b) -> Vec          { ... }   // direct sum: {1 2} ⊕ {3 4} -> {1 2 3 4}
operator ⊖(Vec a) -> Vec                   { ... }   // negation (unary)
operator (Vec a) ⊖ (Vec b) -> Vec          { ... }   // subtraction (binary)
operator (Signal a) ⊛ (Signal b) -> Signal { ... }   // convolution
operator (Signal a) ∗ (Signal b) -> Signal { ... }   // convolution (alternative)

func ∠(Vec a, b) -> Float        { ... }  // angle between two vectors
func ∠(Point3D a, b, c) -> Float { ... }  // angle between three points (vectors ab and bc)

Unclear, if these should have an epsilon (ε) value here. And then they would be function calls, not infix operators:

operator (Vec a) ⟂ (Vec b) -> Bool { ... }   // perpendicular / orthogonal
operator (Vec a) ∥ (Vec b) -> Bool { ... }   // parallel to
operator (Vec a) ∦ (Vec b) -> Bool { ... }   // not parallel to

Set Operators

The set membership/subset symbols parse as relational operators, i.e. they inherit the (infix) fixity and precedence group of the comparison operators:

// Set membership
operator (T x) ∈ (Set<T> s) -> Bool { return s.contains(x) }
operator (T x) ∉ (Set<T> s) -> Bool { return not s.contains(x) }
operator (Set<T> s) ∋ (T x) -> Bool { return s.contains(x) }
operator (Set<T> s) ∌ (T x) -> Bool { return not s.contains(x) }

// Subset / superset
operator (Set<T> a) ⊆ (Set<T> b) -> Bool { return a.isSubsetOf(b) }
operator (Set<T> a) ⊇ (Set<T> b) -> Bool { return a.isSupersetOf(b) }
operator (Set<T> a) ⊂ (Set<T> b) -> Bool { return a.isProperSubsetOf(b) }
operator (Set<T> a) ⊃ (Set<T> b) -> Bool { return a.isProperSupersetOf(b) }

Operator Precedence

List of all currently known operators:

Note
The global precedence ordering should be replaced by partial precedence ordering, as nobody can remember all these precedence levels.

See Carbon Expression Precedence:

Expressions are interpreted based on a partial precedence ordering. Expression components which lack a relative ordering must be disambiguated by the developer, for example by adding parentheses; otherwise, the expression will be invalid due to ambiguity. Precedence orderings will only be added when it’s reasonable to expect most developers to understand the precedence without parentheses.

Also see Circle simpler_precedence

%%{init: {'themeVariables': {'fontFamily': 'monospace'}}}%%
graph BT
    parens["(…)"]

    braces["{…}"]

    unqualifiedName["x"]

    top((" "))

    suffixOps{"x.y
               x.(…)
               x->y
               x->(…)
               x(…)
               x[y]"}

    qualifiedType["const T"]

    pointerType{"T*"}

    pointer{"*x
             &x"}

    negation["-x"]

    complement["^x
                ~x"]

    prefixMath["+x
                √x
                ⊖x"]

    incDec["++x
            --x"]

    unary((" "))

    as["x as T"]

    power[\"x ** y"\]

    multiplication>"x * y
                    x / y
                    x × y
                    x ⋅ y
                    x ⊙ y
                    x ⊘ y
                    x ⊛ y
                    x ∗ y"]

    addition>"x + y
              x - y
              x ⊞ y
              x ⊟ y
              x ⊕ y
              x ⊖ y"]

    modulo["x % y"]

    bitwise_and>"x & y"]
    bitwise_or>"x | y"]
    bitwise_xor>"x ^ y"]

    shift["x << y
           x >> y
           x <<< y
           x >>> y"]

    binaryOps((" "))

    range["x .. y
           x ..< y"]

    threeWay["x <=> y"]

    comparison["x < y
                x > y
                x <= y
                x >= y
                x ≤ y
                x ≥ y"]

    membership["x ∈ y
                x ∉ y
                x ∋ y
                x ∌ y"]

    subset["x ⊆ y
            x ⊇ y
            x ⊂ y
            x ⊃ y"]

    parallel["x ⟂ y
              x ∥ y
              x ∦ y"]

    equality["x == y
              x != y
              x ≠ y"]

    not["not x
         !x
         ¬x"]

    logicalOperand((" "))

    and>"x and y"]
    or>"x or y"]
    xor>"x xor y"]

    andAmp>"x && y"]
    orAmp>"x || y"]

    andSym>"x ∧ y"]
    orSym>"x ∨ y"]
    xorSym>"x ⊻ y"]


    logicalExpression((" "))

    ref["ref x"]

    if>"if x then y else z"]

    insideParens["(…)"]

    assignPlain["x = y"]

    assignArithmetic["x += y
                      x -= y
                      x *= y
                      x /= y
                      x %= y"]

    assignShift["x <<= y
                 x >>= y
                 x <<<= y
                 x >>>= y"]

    assignBitwise["x &= y
                   x |= y
                   x ^= y"]

    assignLogical["x &&= y
                   x ||= y"]

    expressionStatement["x;"]

    top --> parens & braces & unqualifiedName

    suffixOps --> top

    qualifiedType --> suffixOps
    pointerType --> qualifiedType

    pointer --> suffixOps
    negation & complement & prefixMath & incDec --> pointer
    unary --> pointerType & negation & complement & prefixMath

    %% Use a longer arrow here to put `not` next to other unary operators
    not ---> suffixOps

    %% `as` at the same level as comparisons
    as -----> unary

    %% `**` binds tighter than multiplication, looser than the prefix/unary operators
    multiplication --> power
    power --> unary

    modulo & bitwise_and & bitwise_or & bitwise_xor & shift --> unary
    addition --> multiplication
    binaryOps --> addition & modulo & bitwise_and & bitwise_or & bitwise_xor & shift

    %% Ranges bind looser than arithmetic/bitwise, tighter than the relational operators
    range --> binaryOps

    threeWay & comparison & membership & subset & parallel & equality --> range
    logicalOperand --> threeWay & comparison & membership & subset & parallel & equality & not

    %% This helps group the logical operators together
    classDef hidden display: none;
    HIDDEN:::hidden ~~~ logicalOperand

    and & or & xor & andAmp & orAmp & andSym & orSym & xorSym --> logicalOperand
    logicalExpression --> as & and & andAmp & andSym & xor & xorSym & or & orAmp & orSym
    ref & expressionStatement --> logicalExpression
    if ---> ref
    insideParens & assignPlain & assignArithmetic & assignShift & assignBitwise & assignLogical --> if

The graph above covers the partial ordering of all contemplated Unicode/Cilia operators. Relations that most developers can be expected to know are drawn as edges, e.g.

This avoids the well-known C/C++ pitfall where x & mask == 0 parses as x & (mask == 0); here it parses as the intended (x & mask) == 0.

Pairs that nobody reliably ranks are left unordered on purpose and therefore require explicit parentheses, e.g.:

The node shapes encode each group’s

i.e. what it means to chain the same precedence group without parentheses.
Circles are helper nodes only (not a precedence group).

%%{init: {'themeVariables': {'fontFamily': 'monospace'}}}%%
graph LR
    binary@{ shape: brace-r, label: "Binary" }

    nonAssociative["non-associative
    a == b == c
    needs parens"]

    leftAssociative>"left-associative
    a + b + c 
    =
    (a + b) + c"]

    rightAssociative[\"right associative
    a ** b ** c
    =
    a ** (b ** c)"\]


    unary@{ shape: brace-r, label: "Unary" }

    nonRepeating["non-repeating"]

    repeating{"repeating
    x.y.z
    *&x
    T**"}


    helper@{ shape: brace-r, label: "Helper Node" }

    circle((" "))


    binary ~~~ nonAssociative ~~~ leftAssociative ~~~ rightAssociative
    unary ~~~ nonRepeating ~~~ repeating
    helper ~~~ circle

Custom Operators with Declared Precedence

For some symbols fixity and precedence have to be given at declaration.

The two main difficulties (see also the Operators chapter) are:

Modelled after Swift/Haskell, preferably with named precedence groups instead of magic numbers:

operator (Fn f) ∘ (Fn g)         -> Fn     right precedence Composition     { ... }
operator (Matrix a) ⊗ (Matrix b) -> Matrix left  precedence Tensor          { ... }   // tensor / Kronecker product
operator (Set a) ∪ (Set b)       -> Set    left  precedence Union           { ... }   // union
operator (Set a) ∩ (Set b)       -> Set    left  precedence Intersection    { ... }   // intersection (binds tighter than ∪)
operator (Set a) ∖ (Set b)       -> Set    left  precedence Union           { ... }   // set difference: a without b
operator √(Float a)              -> Float                                   { ... }   // unary (prefix by position)

Bracket / “Sandwich” Operator

‖x‖, ⟨a, b⟩ etc. are not infix operators but paired delimiters (“enclosing operator”, “delimited form”, “bracketed expression”, informally “sandwich operator”).

operator ‖Vec v‖ -> Float  { return v.length() }  // norm
operator ⟨T a, b⟩ -> Float { ... }                // inner product

More bracket variants (asymmetric pairs only; some may be used in reversed order, e.g. ≫...≪; see also Unicode Math Brackets):

Pair Category Name / note
⟨...⟩ angle angle brackets (inner product, see above)
⟪...⟫ angle double angle brackets
⦑...⦒ angle angle bracket with dot
⦅...⦆ round double parenthesis
⟮...⟯ round flattened parenthesis
⦃...⦄ curly white curly bracket
⟦...⟧ square white / semantic (“Scott”) square brackets
⦋...⦌ square square bracket with underbar
⦍...⦎ square square bracket with ticks
⦏...⦐ square square bracket with ticks (mirrored)
⁅...⁆ square square bracket with quill
⌊...⌋ floor/ceiling floor (round down)
⌈...⌉ floor/ceiling ceiling (round up)
⦗...⦘ tortoise-shell black tortoise-shell bracket
⟬...⟭ tortoise-shell white tortoise-shell bracket
⦇...⦈ Z notation image bracket
⦉...⦊ Z notation binding bracket
⦓...⦔ arc arc less/greater-than bracket
⦕...⦖ arc double-line arc bracket
⟅...⟆ bag S-shaped bag delimiter
⌜...⌝ corners top corners (quine corners)
⌞...⌟ corners bottom corners
⸢...⸣ corners top half brackets
⸤...⸥ corners bottom half brackets
≪...≫ operator much-less/greater-than (relational operator, not a true bracket)
⋘...⋙ operator very-much-less/greater-than (operator)
‹...› quotation single guillemets (quotation, not math)
«...» quotation double guillemets (quotation, not math)
❨...❩ ornamental parenthesis ornament (decorative)
❪...❫ ornamental flattened parenthesis ornament
❬...❭ ornamental angle bracket ornament
❮...❯ ornamental heavy angle quotation ornament
❰...❱ ornamental heavy angle bracket ornament
❲...❳ ornamental tortoise-shell bracket ornament
❴...❵ ornamental curly bracket ornament

Later / Never

Many of the symbols seem more suitable for a computer algebra system (CAS) than for a general purpose programming language, so they stay unassigned for now.

Reserved for future use, as it could get complicated and confusing. Remaining candidate symbols, not yet assigned to one of the cases above (with their usual mathematical meaning):

OpenMP-like Parallel Programming

TODO
Syntactically this is not a good solution.

  • We avoid brackets in if and while, but then use it for reduce and schedule
  • Syntax should be better, clearer, or more powerful than plain OpenMP, otherwise better use just that.