fsharp / fslang-suggestions

The place to make suggestions, discuss and vote on F# language and core library features
344 stars 20 forks source link

Allow writing an infix expression with not the same oprand type #1372

Open Tangent-90 opened 2 months ago

Tangent-90 commented 2 months ago

I propose we allow writing an infix expression with not the same oprand type

(I do not know how to exactly explain it but it is something like this:

let inline (<<) a x =
  (^t: (member Append: _ -> 't) (a, x))

let s = System.Text.StringBuilder()
s << 1 << 2 << 'a'

The existing way of approaching this problem in F# is ...

Seperate the line by the oprand types

let inline (<<) a x =
  (^t: (member Append: _ -> 't) (a, x))

let s = System.Text.StringBuilder()
s << 1 << 2
s << 'a'

Pros and Cons

The advantages of making this adjustment to F# are make the language consistent

The disadvantages of making this adjustment to F# are no

Extra information

Estimated cost (XS, S, M, L, XL, XXL): Maybe S?

Related suggestions: (put links to related suggestions here)

Affidavit (please submit!)

Please tick these items by placing a cross in the box:

Please tick all that apply:

For Readers

If you would like to see this issue implemented, please click the :+1: emoji on this issue. These counts are used to generally order the suggestions by engagement.

Tangent-90 commented 2 months ago

This seems to be allowed with operators defined in types.

type A() =

  static member (+) (a, b: string) = a
  static member (+) (a, b: int)     = a

A() + 1 + "a"
Martin521 commented 2 months ago

It seems type checking fixes the type of the Append member of the << operator to int -> StringBuilder once it sees s << 1. I guess that, theoretically, this could be kept open (allowing for member overloads). But then we might run into the Swift problem that was discussed on the Discord tech channel just two days ago, namely exploding (worst case: exponential) type checking effort.

T-Gro commented 2 months ago

I think this is a bug in the operator typechecking, we did have a few more reported recently when it comes to chaining of operators on the same line.

Note that in this case, neither parens nor duplicate function resolve the bug here, the same issue remains:

let inline (<<) a x =
  (^t: (member Append: 'a -> 't) (a, x))

let inline (<<<) a x =
  (^t: (member Append: 'b -> 't) (a, x))  

let s = System.Text.StringBuilder()
let res1 = ( s << 1 ) <<< 'c'

FS0001 This expression was expected to have type 'int'
but here has type 'char'