Allow type definitions at expression scope
Submitted by Gustavo Guerra on 3/21/2014 12:00:00 AM
36 votes on UserVoice prior to migration
The suggestion is to allow "type X = ..." in an expression, e.g.
let f () =
type X = A | B
let x = (A,A)
let y = (B,B)
if (x=y) then true else false
Original UserVoice Submission Archived Uservoice Comments
This is a generalization of https://github.com/fsharp/fslang-suggestions/issues/277 .
@dsyme Now that #277 has been approved in principle, any chance that this can be approved as well?
Presumably the scoping here is purely about reducing accessibility, and that these types would be "static" and not have access to variables in the scope. E.g. this would not be allowed:
let y(x:int) =
type T() =
member _.X = x // Error: x is not defined
T().X
This issue is then one of several that are about allowing static things to be defined in smaller scopes:
In all these suggestions, things defined in expression scope could be treated as if defined as private things at a higher level in the same file (the nearest module or namespace). (Except that F# reduces their access to the smaller expression scope rather than the larger private scope.)
I assume it would be OK to keep the type name the same, and give an error there is a name conflict.
module M
// If at least 2 of the three A definitions are present, there is a `duplicate definition of type A`
type A() = class end
let x =
type A() = class end
()
let y =
type A() = class end
()
Alternatively the name could be automatically appended to to give uniqueness.
Alternatively the name could be automatically appended to to give uniqueness.
This will be problematic because once the outer type is shadowed, you cannot access it anymore because expression is not module/namespace
Having nested types inside of F# OOP types would be useful to have as well. It will allow to minimize use of Anonimous Record types and tuples as result of private functions. Example
type External() = **type IntegmediateResult= { A: int; B: int } **let someInternalFunction(): IntegmediateResult = failwith "TODO" **member _.Foo() = ****let i = someInternalFunction(); ****i.A + i.B
I think that IntegmediateResult should be compiled as C# nested type.
@oleksandr-bilyk this example looks like a worse alternative to tuples with named fields https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/value-tuples#tuple-field-names. Also I don't see what's wrong with anonymous records for such case, even allocations doesn't matter because records can be structs
@jl0pd will reply to your comments
@oleksandr-bilyk this example looks like a worse alternative to tuples with named fields https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/value-tuples#tuple-field-names. Also I don't see what's wrong with anonymous records for such case, even allocations doesn't matter because records can be structs
- I provided oversimplified sample. In my real code record type was more complicated.
- I also think that F# should support Tuple Field Names but in my case I needed complex internal structure and wanted record type.
- Complex Anonimous record types when they passed through few private members are not readable well. If forces us to declare type outside of OOP type.
- Ther are nested types in C#. According to .NET Framework Guidelines they may be result of public functions. I wish it be supported by F# as well.