Expose static members of shadowed type abbreviations by functions
I propose we expose static members of type abbreviations.
I can't believe no one has raised this before.
We should be able to shorten System.Int32.TryParse to int.TryParse.
The existing way of approaching this problem in F# is typing the full name out.
Pros and Cons
The advantages of making this adjustment to F# are
- This makes F# even more approachable to beginners, who do not need to know about what the 32 in Int32 means yet.
- C# has had this for years. This bridges the gap between C# and F#. This reduces unpleasant surprises for C# developers coming to F#.
- Type abbreviations shorten long names. Using a static member from the type requires the whole type be typed out again. Frustration and curses then occur.
The disadvantage of making this adjustment to F# is the implementation effort required.
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:
- [X] This is not a question (e.g. like one you might ask on stackoverflow) and I have searched stackoverflow for discussions of this issue
- [X] I have searched both open and closed suggestions on this site and believe this is not a duplicate
- [X] 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:
- [X] This is not a breaking change to the F# language design
- [X] I or my company would be willing to help implement and/or test this
Normally System is open so really its just two characters difference. Int32.TryParse vs int.TryParse
Imagine typing Int32 everywhere instead of int. This was why type abbreviations were added.
In general I'm in favor, though I could see this as being by design from @dsyme's perspective.
This is actually down to a name collision. It's already possible to access static members from type abbreviations. But not if you then bind another value to the same name:
type guid = System.Guid // A type abbreviation
guid.NewGuid() // Accessing a static member works OK
let guid x = System.Guid.TryParse x // Here we define a function with the same name.
guid.NewGuid() // Compiler error. We can no longer access static member
This is exactly what's happening with int. The int function removes the ability to refer to the int type from a value expression. It can only be referred to in a type expression.
I'm not sure if there is a way around this. The compiler would have to work out if you were referring to the value or the type based on the surrounding context. Bear in mind the value could be an object that also has members.
The reason this is easier in C# is that int, float etc. are reserved keywords that can't be used for naming anything else. Trying to introduce that into F# would be a very breaking change. Note that C# has the same limitation for type names that aren't keywords.
I'm personally fine with the possibility of shadowing int, string and I think nowadays it's pretty standard to do so in small function scopes, though I don't do it that much, but I've seen lot of code around.
The way around it is: don't do it if you need the original meaning.
What about:
guid.NewGuid() // There is no "NewGuid" instance method in the guid object. Interpreting as a type instead.
A large part of this is now superseded by #749.
As mentioned above - type abbreviations already support static member lookup. The case of int and string is indeed a clash between int as a value and int as a type abbreviation. The former takes precedence.
I'm not particularly in favour of mod'ing the name resolution rules to allow lookups through single-identifier values and lookups through type names to be combined in one name resolution - though I think that's the logical implication of this suggestion.