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

Shorthand syntax for single case DUs #727

Open
Happypig375 opened this Issue Mar 25, 2019 · 9 comments

Comments

Projects
None yet
9 participants
@Happypig375
Copy link

Happypig375 commented Mar 25, 2019

Title of Suggestion

I propose we add a shorthand syntax for single case Discriminated Unions.

The existing way of approaching this problem in F# is usually repeating the type name.

//Current
type SomeDomainType = SomeDomainType of int
type Temperature = private Temperature of int

//Proposed
type SomeDomainType of int
type Temperature private of int

Pros and Cons

The advantages of making this adjustment to F# are

  1. They are common
  2. It's duplicate information for the reader
  3. The Rename tool in Visual Studio cannot rename both at once because types are not union cases, but they usually take the same name.

The disadvantages of making this adjustment to F# are one more syntax to learn.

Extra information

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

Related suggestions: (put links to related suggestions here)

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
@realvictorprm

This comment has been minimized.

Copy link
Member

realvictorprm commented Mar 25, 2019

I think this is a minor change with big positive impact. Thumbs up! :)

@theprash

This comment has been minimized.

Copy link

theprash commented Mar 25, 2019

The disadvantages of making this adjustment to F# are one more syntax to learn.

Just to expand on this, for people new to F# I've found a common pitfall is to not fully understand the difference between a DU case and the DU type itself. Even after understanding the difference they sometimes conflate these two things for a while. This syntax blurs the boundaries between those two things which could contribute to that misunderstanding.

I would also add as a distinct disadvantage that this would add yet another instance in F# where there are multiple equivalent ways to do exactly the same thing, making it harder to know what's idiomatic and harder to read code in general. I think F# already has more of these than many languages. This is made worse by being a late addition to the language, so even the most idiomatic code will never use this feature if it was written for earlier F# versions.

@sgtz

This comment has been minimized.

Copy link

sgtz commented Mar 25, 2019

at least the way I use them, single case DUs may fragment into n-cases... that's part of the beauty of using them. Visually, I don't see a clear path from the proposed shorthand to the additional cases. Stylistically, I feel it's better to be explicit on this.

@mistiara

This comment has been minimized.

Copy link

mistiara commented Apr 3, 2019

I think this syntax is better suited as a general extension of the existing syntax exception MyException of msg:string, but for normal classes/structs. So it would allow let-fields, inheritance, etc., but also pattern matching over the primary constructor.

Bonus points if we could use the parameters inside the type directly, unlike exception syntax. Silly example:

type HttpHeader of name:string * value:string with
    member __.Formatted = sprintf "%s: %s" name value

Edit: note it would also subsume existing exception syntax:

type TemperatureException of value:int with
    inherit Exception(sprintf "Reached %d degrees" value) // No `this.Message` override needed!
@smoothdeveloper

This comment has been minimized.

Copy link

smoothdeveloper commented Apr 3, 2019

I'm not yet sure about the proposed syntax, as it is not too inconvenient to define a single case DU right now when needed, but it looks fitting idioms.

Is this something that should go along the same line as haskell "newtype" or even related to some degree to units of measures?

@7sharp9

This comment has been minimized.

Copy link
Member

7sharp9 commented Apr 5, 2019

I think this shorthand is too similar to a type alias.

@Happypig375

This comment has been minimized.

Copy link
Author

Happypig375 commented Apr 5, 2019

of stands out a lot more than =.

@charlesroddie

This comment has been minimized.

Copy link

charlesroddie commented Apr 6, 2019

I've found a common pitfall is to not fully understand the difference between a DU case and the DU type itself.

Agreed. Using the same name for the DU type as for one of its cases is confusing. If anything, doing this should be warned about, not encouraged with a shorthand syntax.

@cartermp

This comment has been minimized.

Copy link
Member

cartermp commented Apr 6, 2019

I can certainly sympathize with the existing syntax with single-case DUs today - it kind of sucks, and the tooling point is valid. I wouldn't shocked if it were done differently had F# been first conceived today. However, I think this does break the following design principles:

  • education/learning paths and simplicity
  • does this give multiple ways to achieve the same thing
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.