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

[Proposal] TypeOf over multiple types. #23

Open
AdamSpeight2008 opened this issue Feb 22, 2017 · 23 comments
Open

[Proposal] TypeOf over multiple types. #23

AdamSpeight2008 opened this issue Feb 22, 2017 · 23 comments

Comments

@AdamSpeight2008
Copy link
Contributor

(Ported from Roslyn Repo)

TypeOf ... IsNot ..

If TypeOf obj IsNot TypeA AndAlso
   TypeOf obj IsNot TypeB Then
If TypeOf obj IsNot {TypeA, TypeB} Then

TypeOf ... Is ...

If TypeOf obj Is TypeA OrElse
   TypeOf obj Is TypeB Then
If TypeOf obj Is {TypeA, TypeB} Then

Grammar

TypeOf_Obj	 ::= "TypeOf" ws+ identifier
TypeOf_IsExpr    ::= TypeOf_Obj ws+ "Is" ws+ MatchAgaist
TypeOf_IsNotExpr ::= TypeOf_Obj ws+ "IsNot" ws+ MatchAgainst
MatchAgainst	 ::= Single | MultipleTypes 
SingleType       ::= typeIdentifier
MultipleTypes    ::= '{' typeIdentifier (ws* ',' ws* typeIdentifier)+ ws* '}'

Ruled out TypeOf obj Is ( Type0, Type1. Type2 ) as that conflicts with tuple literal syntax.

@rolfbjarne
Copy link
Member

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).

@AdamSpeight2008
Copy link
Contributor Author

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

@rolfbjarne
Copy link
Member

The And and Or keywords would have to be treated like something other than operators in this context.

@AdamSpeight2008
Copy link
Contributor Author

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)

@Bill-McC
Copy link

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`

@aarondglover
Copy link

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.

@AdamSpeight2008
Copy link
Contributor Author

The use case I've seen are in the expression part of an if-statement.
Select Case ... End Select isn't an expression.

@AdamSpeight2008
Copy link
Contributor Author

AdamSpeight2008 commented May 27, 2017

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

@AdamSpeight2008
Copy link
Contributor Author

AdamSpeight2008 commented Feb 13, 2018

@KathleenDollard @AnthonyDGreen
There is a working proof of concept of this feature in PR #93

@AdamSpeight2008
Copy link
Contributor Author

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

@AdamSpeight2008
Copy link
Contributor Author

@KathleenDollard @AnthonyDGreen I've updated the original post to include the two proposals.

@KathleenDollard
Copy link
Contributor

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?

@AdamSpeight2008
Copy link
Contributor Author

@AdamSpeight2008
Copy link
Contributor Author

  • Proposal 1
    • Good:
      • Visually uncluttered.
      • Once you grasp the concept, I find it easy to understand.
    • Bad:
      • My implementation involves introduce a new syntax node and kind TypeList.
      • Which also a new conceptual form, that isn't (currently) applicable elsewhere.
  • Proposal 2
    • Good:
      • This was the first form I tried when learning TypeOf expressions.
      • Relatively tiny amount of code to implement
    • Bad:
      • Potential to be confused by the false assumption that the operators;-
        Or, OrElse, And, AndAlso
        are restricted to accept expression that evaluate to Boolean values.
      • Changes the semantic meaning for existing non-compiling, so it now compiles.
      • I think it will be possible to add a warning or error, to indicate the feature is only available from a particular version of the language, without affect code using existing old semantics.

@paul1956
Copy link

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.

@AdamSpeight2008
Copy link
Contributor Author

AdamSpeight2008 commented May 27, 2018

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

@paul1956
Copy link

@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).

@AdamSpeight2008
Copy link
Contributor Author

@paul1956 Select TypeOf is a separate proposal.

@paul1956
Copy link

@AdamSpeight2008 I though you were showing me how to do Select TypeOf, I fully support the proposal it is really needed.

@zspitz
Copy link

zspitz commented Aug 30, 2018

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

@zspitz
Copy link

zspitz commented Aug 30, 2018

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.

#277

@jrmoreno1
Copy link

Is there an example where this would be used in the Roslyn codebase?

@paul1956
Copy link

paul1956 commented Jan 8, 2019

@jrmoreno1 It is heavily used in the VB to C# and C# to VB converters but I am not sure where they are today.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

9 participants