dotnet / vblang

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

[Proposal] Selector expressions #596

Open VBAndCs opened 3 years ago

VBAndCs commented 3 years ago

Suppose we have an array named arr, and want to select items > 3:

dim result = arr.Select(function(x) x > 3)

I want to rewrite it like this:

dim result = arr[#Item > 3]

Note: In #556, I asked for allowing [] for arrays and indexer. I am using this here to avoid any confusion with any old code using ().

It items are objects with properties:

dim result = Students.Select(function(x) x.Name)

then:

dim result = Students[#Item.Name]

Which can be shorten to:

dim result = Students[#Name]

note that I previously wanted to use dot instead of #, but this can cause some confusion inside With Blocks.

Now, Suppose we have a list like this:

Dim Students as List(Of Student)

lets complicate the selector a little:

dim result = Students.Select(function(x) x.Address.Street(0) = "a" OrElse x.Address.Street(0) = "a")

or with LinQ:

dim result = from x in Students
                     Let startsWith  = x.Address.Street(0)
                     Where startsWith = "a" OrElse startsWith  = "a"
                     Select x

We can make this shorter by defining a var for the selector and reuse it:

dim startsWith = #Student.Address.Street(0)
dim result = Students[startsWith = "a" orelse startsWith = "b" ]

Note using the type #Student so we avoid late binding and have intellisense support. which can be more compact if VB always the in array syntax:

dim result = Students[startsWith in {"a", "b"}]

or in another way (since the selector is an expression tree, if can be some sort of a function delegate expression:

dim startsWith = #Student.Address.Street.StartsWith
dim result = Students[startsWith("a") orelse startsWith("b") ]

and if add a StartsWithAny extension method to the string class:

dim startsWith = #Student.Address.Street.StartsWithAny
dim result = Students[startsWith({"a", "b"}) ]
VBAndCs commented 3 years ago

I am also thinking of dropping the [] where # exists, so: dim stdunetsNames= Students[#Name] can just be: Dim stdunetsNames= Students#Name where # means: Select the name property of each item in the Students list. Note that stdunetsNames is IEnumerable just like using direct LinQ, so, we can just use it as usual. We can chain selectors as we do with LinQ: Dim stdunetsNames= Students[#Grade > 3]#Name' The '[] are required for conditions, and direct # is best for property selection. I thinl it is not possible to select more than property by this syntax. I may think of: `Dim stdunetsNames= Students[#Grade > 3][(#Name, #Grade)]' but it will be confusing and less readable. I prefer to mix selectors with LinQ in such cases:

Dim stdunetsNames= Students[#Grade > 3].
        Select(Function(x) New with {x.Name, x.Grade})'

Which will be mush better if rewritten as:

Dim stdunetsNames= Students[#Grade > 3].Select(#Name, #Grade)'

And this is where we van rethink of LinQ syntax as:

Dim stdunetsNames= Students Where #Grade > 3
       Select #Name, #Grade
VBAndCs commented 3 years ago

As a special case, dim result = Students[#Name] maybe rewritten as: dim result = Students[ ].Name

pricerc commented 3 years ago
dim result = arr.Select(function(x) x > 3)
. . .
dim result = Students.Select(function(x) x.Address.Street(0) = "a" OrElse x.Address.Street(0) = "a")

Ummm. What are you expecting these to return?

Because, in both cases, result will be an IEnumerable(Of Boolean), which is not what your discussion suggests to me.

It looks like you meant Where, not Select?

VBAndCs commented 3 years ago

It looks like you meant Where, not Select?

My bad :)