Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow all expressions except tuples in property initializers to be unparenthesized #829

Open
Happypig375 opened this issue Jan 22, 2020 · 7 comments

Comments

@Happypig375
Copy link
Contributor

@Happypig375 Happypig375 commented Jan 22, 2020

Title of Suggestion

I propose we allow all expressions in property initializers to be unparenthesized, no matter whether the expression contains <, =, >, & or |.

type T = T with static member M(x: int, y: bool, z: int seq) = ()
let inline ($) a b = a + b

T.M(
    y = true, z = [],
    x = 5 $ 4 // Fails
)

T.M(
    y = true, z = [],
    x = 5 + 4 // Works
)

T.M(
    y = true, x = 5,
    z = seq { yield 5 }  // Works
)

T.M(
    y = true, z = [],
    x = seq { yield 5 } |> Seq.head  // Fails due to the `>` symbol in the pipe
)


T.M(
    x = 5, z = [],
    y = 4 < 3  // Fails
)

T.M(
    x = 5, z = [],
    y = true & false  // Fails
)
T.M(
    x = 5, z = [],
    y = 4 = 3  // Fails
)
T.M(
    x = 5, z = [],
    y = false || false  // Fails
)

All the above fails are due to FS0691: Named arguments must appear after all other arguments.
The existing way of approaching this problem in F# is to parenthesize the expressions. This should be changed to be valid.

Pros and Cons

The advantages of making this adjustment to F# are

  1. Convenience
  2. Meeting expectations of users

The disadvantages of making this adjustment to F# are none that I can think of.

Extra information

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

Related suggestions: https://stackoverflow.com/questions/45137074/f-assigning-inherited-property-values-in-inherited-constructors-parameter-list

Affidavit (please submit!)

Please tick this by placing a cross in the box:

  • This is not a question (e.g. like one you might ask on stackoverflow) and I have searched stackoverflow for discussions of this issue
  • I have searched both open and closed suggestions on this site and believe this is not a duplicate
  • This is not something which has obviously "already been decided" in previous versions of F#. If you're questioning a fundamental design decision that has obviously already been taken (e.g. "Make F# untyped") then please don't submit it.

Please tick all that apply:

  • This is not a breaking change to the F# language design
  • I or my company would be willing to help implement and/or test this
@abelbraaksma

This comment has been minimized.

Copy link

@abelbraaksma abelbraaksma commented Jan 22, 2020

I'm not sure these are called 'property initializers', though I also don't know what the correct term would be otherwise ;).

From the look of it, it appears to me to be a bug in the parser that some infix operators work and others don't. In fact, I'm a bit surprised that an expression like 1 + 2 is fine, but true || false isn't.

@smoothdeveloper

This comment has been minimized.

Copy link
Contributor

@smoothdeveloper smoothdeveloper commented Jan 22, 2020

With this suggestion, how is this handled?

open System.Runtime.InteropServices
type A () =
    static member A(a:int,b:int,c:bool,[<Optional>]d) = a,b,c
    
let d = true
let c = true

A.A(a=5|||4, b= 4&&&5, c = d, d = c,c)

Isn't there cases with lambda also where it would lead to similar inconsistency?

@abelbraaksma

I'm not sure these are called 'property initializers',

you are right, I'd call those named method arguments, and it also has something to do with methods returning types that have setable properties (that can be set with extra named arguments), this applies to constructor and method alike AFAIK.

@Happypig375

This comment has been minimized.

Copy link
Contributor Author

@Happypig375 Happypig375 commented Jan 22, 2020

A tuple expression should still be parenthesized. Let me edit this.

@Happypig375 Happypig375 changed the title Allow all expressions in property initializers to be unparenthesized Allow all expressions except tuples in property initializers to be unparenthesized Jan 22, 2020
@Happypig375

This comment has been minimized.

Copy link
Contributor Author

@Happypig375 Happypig375 commented Jan 22, 2020

@smoothdeveloper

A.A(a=5|||4, b= 4&&&5, c = d, d = c)

is equal to

A.A(a=(5|||4), b= (4&&&5), c = d, d = c)

Iirc, boolean expressions cannot appear directly in method arguments as they are interpreted as named arguments. They have to be parenthesized.

@Happypig375

This comment has been minimized.

Copy link
Contributor Author

@Happypig375 Happypig375 commented Jan 22, 2020

type C() =
    member this.M(x:bool) = ()
    member this.N() =
        let y = 1
        this.M(y = 1)
        // error FS0495: The member or object constructor 'M' has no argument or settable return property 'y'. The required signature is member C.M : x:bool -> (unit -> bool).
        this.M(1 = y) // Works
@Happypig375

This comment has been minimized.

Copy link
Contributor Author

@Happypig375 Happypig375 commented Jan 22, 2020

@smoothdeveloper
According to the docs, normal methods do not have "Assigning values to properties at initialization".

@smoothdeveloper

This comment has been minimized.

Copy link
Contributor

@smoothdeveloper smoothdeveloper commented Jan 22, 2020

@Happypig375 AFAIK, it just works the same as constructors, and is really convenient (in real code).

Short sample:

type A() =
    let mutable v = 0
    member this.V 
      with get () = v
      and set (value) = v <- value

type B = 
  static member B () = A()


let a = B.B(V=3)
printfn "%i" a.V
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
3 participants
You can’t perform that action at this time.