Open AdamSpeight2008 opened 7 years ago
I'm not sure I like this, but an improvement might be to allow Or
or And
instead of commas to separate the types.
This means your examples become:
If TypeOf obj IsNot {TypeA And TypeB} Then
If TypeOf obj Is {TypeA Or TypeB} Then
And it also allows you to test if a type implements multiple interfaces:
If TypeOf obj Is {InterfaceA And InterfaceB} Then
A downside is that it sounds grammatically weird in the negative case (IsNot .. Nor
would sound better than IsNot ... And
, but that would introduce another keyword for a dubious reason).
The issue with TypeA And TypeB
and TypeA Or TypeB
is that they are operators, and would affect the order of evaluation. Eg
If TypeOf obj IsNot {TypeA And TypeB} Then
' becoming
If TypeOf obj IsNot {Boolean} Then
The And
and Or
keywords would have to be treated like something other than operators in this context.
Alternative Syntax is to use the syntax of generic type parameters.
TypeOf obj Is (Of T0, T1, T2)
TypeOf obj IsNot (Of T0, T1, T2)
I wonder if we can relax the rules around Select Case such that Is doesn't require a comparison operator when using a Select Case TypeOf(obj) eg: `Select Case TypeOf(obj) Case Is T1, T2, T3
Case Else
End Select`
If Mads and the other c# fan boys didnt believe that Pattern Matching is too much for the simple brain of a VB developer then there wouldn't be much need to do the select case approach and VB would have a powerful feature.
The use case I've seen are in the expression part
of an if-statement
.
Select Case ... End Select
isn't an expression.
@AnthonyDGreen
I am looking at implementing this feature, in the form.
~TypeOf obj Is (Of T0, T1)
~ TypeOf obj Is { T0,T1 }
(in a prototype form)
Initial research suggest that I'd only need to change the binder to bind to ~generic type parameter list~ and new type TypeArray
. Then in lowering apply the compiler generated transform the to the expanded version.
@KathleenDollard @AnthonyDGreen There is a working proof of concept of this feature in PR #93
@rolfbjarne I going experiment with TypeOf expr Is T1 Or T2 Or T3
as I think it maybe possible to support, by manipulating the lowering.
(TypeOf expr Is T1 Or T2 Or T3) ==>
( (TypeOf expr Is T1) Or (TypeOf expr Is T2) Or (TypeOf expr Is T4)
@KathleenDollard @AnthonyDGreen I've updated the original post to include the two proposals.
I've been traveling and balancing a family illness, so not as responsive as I'd like to be, and the VB LDM has missed a number of meetings. Explaining the silence on this.
@aarondglover Your comment on Mads and the managed language team is not correct. Folks on the team do not believe that VB programmers have "simple brains."
The C# community is taking two steps in to pattern matching. The structural one already taken and the functional one on the table for C# 8. We don't know if pattern matching will be in an upcoming version of VB, but if it is, VB will hopefully take a single step into expressions (perhaps also with structural).
I'm afraid I'm struggling to see the value in this proposal. My personal comprehension of the current is better than the proposed. Is there a win other than in comprehension and can folks weigh in on whether they see a big win in the proposed on comprehension?
@KathleenDollard @AnthonyDGreen I've mocked up a example of each based on a vb file in Roslyn repo. Original Example
Proposal 1: Example Using TypeOf Expressions with TypeListSyntax
TypeList
.Or
, OrElse
, And
, AndAlso
are restricted to accept expression that evaluate to Boolean
values.There are two patterns that appear all over my code, the first would be a lot simpler to express if I could just list out all the possibilities, and for the second I need a Select statement that works with TypeOf and Is. How you implement it I don't care. I don't see the value in C#'s DeclarationPattern for VB unless everything is declared Object or Infer is On, two things I personally don't like, or VB has local Options where I could allow Infer On just around pattern matching.
{If or Return} TypeOf statement Is CSS.BreakStatementSyntax OrElse
TypeOf statement Is CSS.ContinueStatementSyntax OrElse
TypeOf statement Is CSS.ExpressionStatementSyntax OrElse
TypeOf statement Is CSS.ReturnStatementSyntax OrElse
TypeOf statement Is CSS.ThrowStatementSyntax OrElse
TypeOf statement Is CSS.YieldStatementSyntax
and
If TypeOf exprNode Is Syntax.CasePatternSwitchLabelSyntax Then
Dim ConstantPattern As ConstantPatternSyntax = CType(PatternLabel.Pattern, ConstantPatternSyntax)
...
ElseIf TypeOf exprNode Is Syntax.ObjectCreationExpressionSyntax then
...
ElseIf TypeOf exprNode Is Syntax.SwitchLabelSyntax Then
...
ElseIf TypeOf exprNode Is Syntax.DeclarationPatternSyntax Then
...
Else
...
End If
I used Roslyn Types here but this applies to VB Forms as well where you frequently want to change some common control property and need to cast if first before the property is available with Options Strict and Explicit On.
@paul1956 Your first example is what this proposal is specifically targeting. Using TypeList Syntax
{If or Return} TypeOf statement Is { CSS.BreakStatementSyntax,
CSS.ContinueStatementSyntax,
CSS.ExpressionStatementSyntax,
CSS.ReturnStatementSyntax,
CSS.ThrowStatementSyntax,
CSS.YieldStatementSyntax}
Using TypeOf Operators Syntax
{If or Return} TypeOf statement Is CSS.BreakStatementSyntax OrElse
CSS.ContinueStatementSyntax OrElse
CSS.ExpressionStatementSyntaxm OrElse
CSS.ReturnStatementSyntax OrElse
CSS.ThrowStatementSyntax OrElse
CSS.YieldStatementSyntax
If we take this code sample, which is similar in form to your second example and use Select TypeOf
Public Overrides Function GetAttributeNodes(node As SyntaxNode) As IEnumerable(Of SyntaxNode)
Select TypeOf node
Case CompilationUnitSyntax Out result : Return GetAttributeNodes(result.Attributes)
Case TypeBlockSyntax Out result : Return GetAttributeNodes(result.BlockStatement.AttributeLists)
Case EnumBlockSyntax Out result : Return GetAttributeNodes(result.EnumStatement.AttributeLists)
Case DelegateStatementSyntax Out result : Return GetAttributeNodes(result.AttributeLists)
Case DeclareStatementSyntax Out result : Return GetAttributeNodes(result.AttributeLists)
Case MethodStatementSyntax Out result : Return GetAttributeNodes(result.AttributeLists)
Case MethodBlockBaseSyntax Out result : Return GetAttributeNodes(result.BlockStatement.AttributeLists)
Case PropertyBlockSyntax Out result : Return GetAttributeNodes(result.PropertyStatement.AttributeLists)
Case PropertyStatementSyntax Out result : Return GetAttributeNodes(result.AttributeLists)
Case EventBlockSyntax Out result : Return GetAttributeNodes(result.EventStatement.AttributeLists)
Case EventStatementSyntax Out result : Return GetAttributeNodes(result.AttributeLists)
Case FieldDeclarationSyntax Out result : Return GetAttributeNodes(result.AttributeLists)
Case ParameterSyntax Out result : Return GetAttributeNodes(result.AttributeLists)
Case ModifiedIdentifierSyntax Out result : Return GetAttributeNodes(result.Parent)
Case VariableDeclaratorSyntax Out result : Return GetAttributeNodes(result.Parent)
End Select
Return SpecializedCollections.EmptyEnumerable(Of SyntaxNode)()
End Function
The Out result
is scoped to only the Case Block
it is on. eg
Case CompilationUnitSyntax Out result : Return GetAttributeNodes(result.Attributes)
' ...
Case CompilationUnitSyntax
Dim result As CompilationUnitSyntax = DirectCast(node, CompilationUnitSyntax)
Return GetAttributeNodes(result.Attributes)
Which why we can reuse result
in subsequent Case Statements.
@AdamSpeight2008 I agree with your first comment, I was addressing the need question from @KathleenDollard. We need a simpler solution,
I have tried to use Select TypeOf and cant find any syntax where it don't get errors. I my actual usage I am usually doing a lot more work and don't need a single line version. I typically want to do the cast to a new variable and operate on the result, so scope is also not an issue and, that is why in my example I showed the CType (I did notice that I could use DirectCast., thanks for the tip).
@paul1956 Select TypeOf is a separate proposal.
@AdamSpeight2008 I though you were showing me how to do Select TypeOf, I fully support the proposal it is really needed.
A generalized pattern matching syntax would combine the OR
pattern and the type-check pattern, to get the same result as this proposal:
Dim o As Object
'...
If o Matches TypeA, TypeB Then
or, if the type-check pattern syntax is not optional:
Dim o As Object
'...
If o Matches Of TypeA, Of TypeB Then
I would also suggest that just as we don't have a ValueOf
keyword:
Dim x = 5
If ValueOf x < 10 Then
but instead we compare directly the value of x
:
Dim x = 5
If x < 10 Then
so too on a conceptual level we aren't interested in the type per se, but rather in does this object support this type? --
Dim o As Object
'...
If o Is IEnumerable Then
and it's unfortunate that Is
is already taken, as testing for reference equality. But we shouldn't introduce new uses of TypeOf
where it is unnecessary.
Is there an example where this would be used in the Roslyn codebase?
@jrmoreno1 It is heavily used in the VB to C# and C# to VB converters but I am not sure where they are today.
(Ported from Roslyn Repo)
TypeOf ... IsNot ..
TypeOf ... Is ...
Grammar
Ruled out
TypeOf obj Is ( Type0, Type1. Type2 )
as that conflicts with tuple literal syntax.