dotnet / vblang

The home for design of the Visual Basic .NET programming language and runtime library.
290 stars 64 forks source link

Composable types? #166

Open xieguigang opened 6 years ago

xieguigang commented 6 years ago

When we declare a generic Function/Type, we can compose the generic type constraint from multiple types, for example:

' declare a generic type with composable type constraint
Public Class Foo(Of T As {IComparable(Of T), IEnumerable(Of String)})
    ' ....
End Class

' or declare a generic function with composable type constraint
Public Sub Foo(Of T As {IComparable(Of T), IEnumerable(Of String)})(obj As T)
End Sub

Recently, a serials of type pattern programming feature was proposed by @AdamSpeight2008:

All these issue are talking about the type match in pattern way. And what about produce object from such type pattern? @zspitz proposal declare a composable type at this issue for such type pattern generation, but the syntax is too much complicated. And in my opinion, for declare a composable type, the declare statement format can keeps the same as the generic type constraint:

Dim obj As {IComparable(Of T), IEnumerable(Of String)}

Advantage

  1. Improvements on the coding experience, less type casting, less coding, save our time
  2. Safer than using Object type
  3. Especially helpful on Factory Design Pattern
Using Object
Public Function Factory(type As type) As Object

    ' template type for produce the factory product 
    ' should implements all of the interface type andalso 
    ' inherits from a specific base type.
    If Not type.IsInheritsFrom(GetType(OtherType)) OrElse 
       Not {
            GetType(IComparable(Of String)), 
            GetType(IEnumerable(Of Char)), 
            GetType(IList(Of Char()))
        }.All(Function(t) 
                  Return type.ImplementInterface(t)
              End Function) Then

        Return Nothing
    End If

    Dim obj As Object = Activator.CreateInstance(type)

    ' In current version of VisualBasic, obj can not declared as a composable type, 
    ' so that the type casting is required!
    ' too much inconvenience 
    Call DirectCast(obj, OtherType).BlaBlaBla()
    Call DirectCast(obj, IList(Of Char())).AddRange("1234")

    ' blabla

    Return obj
End Function
Using Composable type
Public Function Factory(type As type) As Object

    ' template type for produce the factory product 
    ' should implements all of the interface type andalso 
    ' inherits from a specific base type.
    If Not type.IsInheritsFrom(GetType(OtherType)) OrElse 
       Not {
            GetType(IComparable(Of String)), 
            GetType(IEnumerable(Of Char)), 
            GetType(IList(Of Char()))
        }.All(Function(t) 
                  Return type.ImplementInterface(t)
              End Function) Then

        Return Nothing
    End If

    Dim obj As {
        OtherType, 
        IComparable(Of String), 
        IEnumerable(Of Char), 
        IList(Of Char())
    } = Activator.CreateInstance(type)

    ' due to the reason of obj is a composable type, 
    ' so that the type casting operation will no longer required.
    Call obj.BlaBlaBla()
    Call obj.AddRange("1234")

    ' blabla

    Return obj
End Function
zspitz commented 6 years ago

@xieguigang

the syntax is too much complicated

The syntax currently used for generic constraints describes only intersection types (something which is both IComparable(Of T) and IEnumerable(Of String)). I don't see any natural way to extend this to union types (something which could be either an IComparable(Of T) or an IEnumerable(Of String)).

My proposed syntax allows for both union types and intersection types, and as an added benefit, removes the curly braces:

'intersection type
Dim obj As IComparable(Of T) And IEnumerable(Of String)
'with optional parentheses
Dim obj As (IComparable(Of T) And IEnumerable(Of String))

'union type
Dim obj As (String Or System.Random)
obj = "abcd"
obj = New System.Random()

Your mention of the Factory design pattern illustrates another use case for union types:

Public Function Factory(condition As String) As String Or Number Or System.Random
    Select Case condition
    Case "string"
        Return "abcd"
    Case "number"
        Return 15
    Case "random"
        Return New System.Random()
    End Select
End Function

If the use cases for union types (type checking against one of a set of types, factory methods, consolidation of function overloads) are non-goals, then I agree that there is no real need to introduce a new syntax for intersection types; we should stick with the old one.

nathanstites commented 6 years ago

Love the AND and OR idea for this.

AnthonyDGreen commented 6 years ago

Can you point to some real-world code examples that would benefit from this feature? The factory pattern is a bad example since traditionally factories return a concrete instance of some known abstract type like DbConnection, not Object, so that consumers can work with said objects concretely.

zspitz commented 6 years ago

@nathanstites This proposal is only about applying the existing syntax used for multiple types in generic constraints to variable definitions (Dim obj As {IComparable(Of T), IEnumerable(Of String)}).

If you like the And/Or, I suggest you see (and upvote) my original proposal (https://github.com/dotnet/vblang/issues/47).

zspitz commented 6 years ago

@AnthonyDGreen @reduckted The use cases for this also include multitype checking:

If TypeOf x Is {MyClass, MyInterface} Then

and the use of members from both type parts, as you mentioned here.