Search code examples
f#operator-overloadingdollar-sign

Why is $ allowed but $$, or <$> disallowed as an operator (FS0035) and what makes $ special?


$ is allowed in a custom operator, but if you try to use $$, <$> or for instance ~$% as operator name you will receive the following error:

error FS0035: This construct is deprecated: '$' is not permitted as a character in operator names and is reserved for future use

$ clearly also has the '$' in the name, but works, why? I.e.:

let inline ( $ ) f y = f y

// using it works just fine:
let test = 
    let add x = x + 1
    add $ 12

I see $ a lot in online examples and apparently as a particular kind of operator. What is this spcial treatment or role for $ (i.e. in Haskell or OCaml) and what should <$> do if it were allowed (edit)?

Trying to fool the system by creating a function like op_DollarDollar, doesn't fly, syntax check is done on the call site as well. Though as an example, this trick does work with other (legal) operators:

// works
let inline op_BarQmark f y = f y
let test = 
    let add x = x + 1
    add |? 12

// also works:
let inline op_Dollar f y = f y
let test = 
    let add x = seq { yield x + 1 }
    add $ 12

Solution

  • There's some inconsistency in the F# specification around this point. Section 3.7 of the F# spec defines symbolic operators as

    regexp first-op-char = !%&*+-./<=>@^|~ 
    regexp op-char       = first-op-char | ? 
    
    token quote-op-left  =
        |  <@ <@@  
    
    token quote-op-right  =
        |  @> @@>  
    
    token symbolic-op  =
        | ?
        | ?<-
        | first-op-char op-char*
        | quote-op-left
        | quote-op-right
    

    (and $ also doesn't appear as a symbolic keyword in section 3.6), which would indicate that it's wrong for the compiler to accept ( $ ) as an operator.

    However, section 4.4 (which covers operator precedence) includes these definitions:

    infix-or-prefix-op :=
        +,  -, +., -., %, &, && 
    
    prefix-op :=
        infix-or-prefix-op
        ~ ~~ ~~~             (and any repetitions of ~)
        !OP                  (except !=) 
    
    infix-op :=
        infix-or-prefix-op  
        -OP +OP || <OP >OP = |OP &OP ^OP *OP /OP %OP !=  
                             (or any of these preceded by one or more ‘.’) 
        := 
        :: 
        $ 
        or 
        ?
    

    and the following table of precedence and associativity does contain $ (but no indication that $ can appear as one character in any longer symbolic operator). Consider filing a bug so that the spec can be made consistent one way or the other.