dotnet / vblang

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

[Proposal] CType pattern matching operator #542

Open VBAndCs opened 4 years ago

VBAndCs commented 4 years ago

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 commented 4 years ago

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 commented 4 years ago

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 commented 4 years ago

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 commented 4 years ago

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 commented 4 years ago

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:

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 commented 4 years ago

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 commented 4 years ago

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:

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 commented 4 years ago

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 commented 4 years ago

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

VBAndCs commented 4 years ago

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 commented 3 years ago

【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 commented 3 years ago

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 commented 3 years ago

Why not "As"?