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] CType pattern matching operator #542

Open
VBAndCs opened this issue Jul 9, 2020 · 13 comments
Open

[Proposal] CType pattern matching operator #542

VBAndCs opened this issue Jul 9, 2020 · 13 comments

Comments

@VBAndCs
Copy link

VBAndCs commented Jul 9, 2020

I suggest a new usage of the CType operator to be used in pattern matching like this:

If CType(Obj, s As String) AndAlso s.Lenght > 0 then

End If

The CType here returns true if obj is not nothing and the cast is possible otherwise false.
The second operand must contain a var declaration.
Comparing
CType(Obj, s As String) (2 keys words: CType, As)
to
TypeOf Obj Is s As String (3 keys words: TypeOf, Is, As)
and:
TypeOf Obj Is String Into s (3 keys words: TypeOf, Is, Into)

In my opinion, it is the most readable, meaningfull and shortest syntax possible, without the need of any new keyword.

Note: If we omit the var As part, we will have the old CType operation, with a possible invalid cast exception:

If CType(Obj, String).Lenght > 0 then

End If

Note also I suggest to apply the same syntax everywhere needed, such as in0-place out params:
Dim I = Integer.TryParse(x, n As Integer)

@zspitz
Copy link

zspitz commented Jul 9, 2020

Or perhaps:

If obj Matches String Into s AndAlso s.Length > 0 Then
End If

Two keywords, no parentheses, and doesn't repurpose an existing keyword for wildly different behavior:

Dim o As Object = 5
Dim result1 = CType(o, Random) ' throws a runtime exception
Dim result2 = CType(o, rnd As Random) ' returns a boolean

A side benefit is avoiding the unclear mess that is the TypeOf syntax.

@VBAndCs
Copy link
Author

VBAndCs commented Jul 9, 2020

Matches is a new keyword (a breaking change) in a wrong context. It refers to regular expressions and doesn't indicate types. Besides, this a bad usage of a new keyword. I would suggest:
obj Matches s As String
I hate to use the word Into in this matter.
I first thought of:
obj CastsTo s As String
but this quickly brings up CType, and I found that:
CType(obj, s As String)
is the perfect one for the job. It has a form of a function, but it is a keyword and this can allow us to modify the syntax as we want adding a declaration part. I fall in love with it in a glimpse.

I see no deal of have two formulas of CType. It will not break anything, and we have many keywords with different usages, such as conditional If and ternary If.

@zspitz
Copy link

zspitz commented Jul 9, 2020

Matches is a new keyword ... in a wrong context. It refers to regular expressions and doesn't indicate types.

When you work with regular expressions, you write a pattern (using regular expression syntax) and check if a string matches the pattern; you can optionally capture parts of the string that match subpatterns. That is precisely the model for pattern matching (note: not just type-check-and-cast) -- does the subject of the Select match any of the Case patterns? And if it does, optionally extract all or some into a new variable or variables.

But you seem to conflate generalized pattern matching with type-check-and-cast (as evidenced by the title of this issue). VB.NET already has a limited form of pattern matching, unrelated to type checks:

Dim i = 17
Select i
    Case 1
    Case 5 To 20 ' range pattern
    Case < 0, > 100 ' OR pattern
End Select

and in the context of generalized pattern matching, I think it more sensible to put the pattern before the (optional) variable introduction/extraction.

@VBAndCs
Copy link
Author

VBAndCs commented Jul 9, 2020

I am against the C# type-b4-var style, period. It is not a VB style and must not be. We are not writing an essay here to think what should comes first. A programming language is a set of rules that programmers learn and use. My suggestions follows the VB.NET common sense, and this is how I would like to have this feature. In fact I hate most of C# new syntax, esp switch expression and decided not to ever use it! I will not contaminate my code with such abomination syntax. So, the only logic here is the VB.NET lang logic. We should understand the meaning from our general knowledge about the language. Matches will not satisfy that, but CType will.

@zspitz
Copy link

zspitz commented Jul 9, 2020

I am against the C# type-b4-var style, period. It is not a VB style and must not be.

You're not alone. Eric Lippert lists the C# variable declaration style as one of the 10 worst C# features (see # 5).

But Into is no less a part of VB.NET syntax.

We need to clarify what the goal is here:

  • Is the goal only to simplify this idiom?

    Dim o As Object
    If TypeOf o Is String Then
        Dim s = CType(o, String)
        Console.WriteLine(s.Length)
    End If
    

    Then we can adjust the language to not require a separate variable (Option Infer Turbo (aka Smart Variable Typing) #172):

    Dim o As Object
    If TypeOf o Is String Then Console.WriteLine(o.Length)
    

    and extended to Select:

    Select o
        Case String
            Console.WriteLine(o.Length)
        Case Integer
             Console.WriteLine(o * 5)
    End Select
    
  • Is the goal to provide a generalized pattern matching syntax, for different kinds of patterns, not just type-checking-and-variable? Then every usage of patterns has two parts:

    1. does this object/value match the pattern we are testing against, and
    2. the (optional) extraction of all or parts of the original object/value to additional variable(s).

    For this, it makes more sense to put the pattern first, because the pattern test is the first step; which information goes into which variables is invariably secondary to the pattern match itself.

    This has nothing to do with VB.NET-style variable declaration vs C#-style variable declaration. The pattern could be unrelated to type checking, such as:

    Dim s As String
    Select s
        Case "a" To "z" Into lowercase, "A" To "Z" Into uppercase
    End Select
    

    or checking for public properties, without checking the type of the object itself:

    Dim o As Object
    Select o
        Case With {.LastName Matches String Into lname, .FirstName Matches String Into fname}
          Console.WriteLine($"Last name = {lname}, First name = {fname}")
    End Select
    

So, the only logic here is the VB.NET lang logic.

And VB.NET already has a model for generalized pattern matching, albeit a severely limited one: the various patterns that can follow each Case clause in a Select Case. Applying a similar model to any boolean context (If ... Then, Do ... While) seems worth a single new keyword.

Matches will not satisfy that, but CType will.

As noted, if the goal is a generalized pattern matching syntax, CType is almost irrelevant.

@VBAndCs
Copy link
Author

VBAndCs commented Jul 9, 2020

As I said about C#, this is a kind of contaminating the language!
Yesterday, I brought up the C# complexity issue in csharp room on gitter, and I want to quote @mikernet reply to me:

I'm used to C# syntax and although I relatively regularly have to read or convert snippets of code in VB I always struggle a bit with it because I just don't use it enough. I'm sure I could become just as comfortable as I am with C# but it's just a matter of familiarity with a particular syntax.

I can empathize with people learning C# somewhat recently and thus haven't been using it for the last 20 years. I've had the opportunity to start at the beginning with a slow and progressive build-up to the point where the language is now. C# is waaaaay harder to start learning now and has become a bit of a nightmare for newer developers - my onboarding time for a student intern to become somewhat capable of contributing effectively to our projects has increased very dramatically over the years and I can only see that getting worse. At this point, my intern placements are just fun charity work for the local community.

The C# language team has decided the things it values and making the language simple to reason about is definitely not a top priority. For better or worse, performance and other factors take the front seat.

I have more to say in next reply: ....

@VBAndCs
Copy link
Author

VBAndCs commented Jul 9, 2020

When any language wants to add a new feature, it must follow these rules:

  1. Not to make the language harder to learn for beginners.
  2. Not to make the syntax harder to read and understand for all programmers including beginners.
  3. Make programmers type as less as possible, but not on the expense of 1 and 2. Shorter syntax can be harder to understand. It can be simple, but when combined with other syntax appear complex and confusing (I gave an example of a C# expression bodied local function that uses a turnery if)!

So, this is why I hate most of pattern matching in C# and will never use them in my code.

My vision of VB in all my proposals is to achieve the above goals, so any beginner takes the first look at the language finds it:

  • less verbose, and compact.
  • easy to read and understand.
  • Clever and smart to get what he means.

Any feature that breaks these expectation must be avoided. For example:

Dim s As String
Select s
    Case "a" To "z" Into lowercase, "A" To "Z" Into uppercase
End Select

What can I do with two different vars in one case?
Obviously I will need to write If statement on lowercase and uppercase (in fact they have to be nullable to have control over them)
So, the smart thing to do is to have two cases, and then we can use s directly in each case with no need for additional vars:

Dim s As String
Select s
    Case "a" To "z" 

    Case "A" To "Z" 
End

So, why we have to contaminate the language with such complexity?
All I want to save the programmer's time in writing and reading the code, without making the language harder for beginners and maintainers.
We should all hold this goal in our proposals, and not be rush to copy new features from C#. VB as it is today can do every thing without any more features. Any language with variables, arithmetic operations, conditions, loops and Functions can do it all. I have no problem with freezing VB.NET, but the real problem is that MS is keeping it away from all new technologies, which takes it out of the market.

@VBAndCs
Copy link
Author

VBAndCs commented Jul 9, 2020

It would be better if we can use TryCast instead of CType in my proposal:

If TryCast(Obj, s As String) AndAlso s.Lenght > 0 then

End If

but TryCast(Obj, s As String) should return a boolean. It will not break since the part s As String is not valid today, but it can be a bit confusing! In fact this is how should TryCast invented from beginning to avoid having to use nullable values instead of value types, and have the cast and the check in one step.

@AdamSpeight2008
Copy link
Contributor

AdamSpeight2008 commented Jul 9, 2020

What's stopping you implementing it in your own fork?

@VBAndCs
Copy link
Author

VBAndCs commented Jul 9, 2020

I didn't master the source yet. It is huge. I am studying Small basic source code now, and will use it as a test lab. It is a very small lang, and I will enjoy completing it and building my VB on top of it, before tampering with Roslyn.

@kingtu
Copy link

kingtu commented Dec 11, 2020

【Thus】 is a good word (idea)

Dim o As Object
If TypeOf o Is String Thus s Andalso s.Length>0 Then
Console.WriteLine(s.Length)
End If

@kingtu
Copy link

kingtu commented Dec 11, 2020

Dim o As Object
select o
case 1,2 thus A
Console.WriteLine(A)
case "1","2" thus B
Console.WriteLine(B.Length)
end select

@paul1956
Copy link

Why not "As"?

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

No branches or pull requests

5 participants