Open VBAndCs opened 4 years ago
I don't like this. Like the majority of your proposals, this is just needlessly increasing the complexity of the language just to save a few keystrokes. This is especially damning when you consider that verbosity and clarity is VB's primary strength.
or use the 'language integrated' query syntax.
Dim x = From i In items Select i.id
Dim y = From i In items Select i.id & ", " & i.Text
which is less typing than current lambda syntax, and clearer.
Having said that, I would have some sympathy with and implied 'with':
Dim x = From i In items Select .id
Dim y = From i In items Select .id & ", " & .Text
provided the members are unambiguous, otherwise they would need to be qualified.
I haven't been a fan of With
blocks since they prevented me from using edit-and-continue debugging (which probably dates me). And I don't see this as a necessarily 'breaking' change - if the .
properties are within an existing With
block, then the With
block 'wins'; otherwise the introduction of LINQ with From
could trigger an 'implied' With
for the duration of that statement.
However, I'm not sure how well it would work with lambda syntax - I think it would get very cluttered very quickly and I'm not sure it would suit My ideas about what VB should look like :smile:
As for:
Imports myList = List(Of (Id As Integer, Text As String))
you can achieve that almost exactly with
Class MyList : Inherits List(Of (Id As Integer, Text As String)) : End Class
I couldn't quite figure out what your SetItemsSorce
methods were trying to do - they don't compile as-is, it looks like there's an overload missing (one that takes an observable collection as a parameter). But I think
Dim texts = New ObservableCollection(Of String)(From i In items Select i.Text)
is quite easy to read. Or if you have the appropriate extension method in a library somewhere:
Dim texts = (From i In items Select i.Text).ToObservableCollection()
this is just needlessly increasing the complexity of the language just to save a few keystrokes
All these proposals aim to make the language more readable and simple. Give the 2 syntax forms to beginners and take a survey. You think that current lambda syntax is easy and more readable? Strange! The language as is, is too complex for beginners, lost many of them over last decade, and is now frozen to death. Thinking otherwise will send it to oblivion for good.
LinQ which is less typing than current lambda syntax
LinQ is a bit easier but is never less typing than lambdas syntax! Every syntax has its advantages: LinQ is more readable in complex queries. Lambdas with more than one param can be better in some situations, especially when has a full body and complex statements. The dot syntax covers the common ground where we deal with one record (one param) and only need to get a one filed or a calculated value on it. This is a dominant case in Razor syntax, and a daily case in normal code, where writing LinQ inside with blocks will only make it worst!
Note:
I avoid .EF core fluent API as long as I can send the field name as a string. It is insanely influent API (even in C#) and naming it fluent with this lambda syntax is a funny joke. The dot syntax is better than sending the string name (with no intellisense and possible typos), and still one char less ((.Name) vrs
("Name")`
I so enough of single-line single-param single-field-result lambdas, and don't want to use this syntax anymore.
this is just needlessly increasing the complexity of the language just to save a few keystrokes
All these proposals aim to make the language more readable and simple. Give the 2 syntax forms to beginners and take a survey. You think that current lambda syntax is easy and more readable? Strange! The language as is, is too complex for beginners, lost many of them over last decade, and is now frozen to death. Thinking otherwise will send it to oblivion for good.
In what world is
Public Sub SetItemsSorce(items As List(Of (Id As Integer, Text As String)))
SetItemsSorce(
items.Select(.Id).ToList,
New ObservableCollection(Of String)(items.Select(.Text))
)
End Sub
obvious in its intent? The only indication that .Id
is a lambda and not a field/property access, is that your method lacks a With
statement. The only way it will ever become obvious if one is intimately familiar with the syntax in question. That is not a sign of a beginner friendly language.
There's also the fact that your proposal only covers a single use case for inline functions. If you ever need to do anything else? Whoops, you're back to using the current syntax. Or are you going to make a new proposal for each and every time you need an inline method that your previous ones don't cover?
On the other hand, while the current inline method syntax is clunky, at least it is clear you are writing one and that it works for any conceivable purpose.
The only indication that .Id is a lambda and not a field/property access, is that your method lacks a With statement.
Read the whole proposal. This is not the only suggested syntax, so, go with what you see suitable.
Besides, nowadays app code is impossible to understand outside the editor, because the API is independent on the lang, and each API has its purpose and usage. The intent is fully clear from the Select signature that expects a lambda, so, if you send even there is a with block, you will get a compiler error, unless the .ID returns a delegate! Also, ypu should read my prev reply cerfully, as lambdas not only represent delegates but also expression trees! This is heavly used in Razor and EF, and need simplification if we ever wish to take VB there.
your proposal only covers a single use case for inline functions
And this is more than enough, as it covers a wide range of usage.
I have no issue with writing full lambda functions, as it looks like a normal function but defined in place without a name. It can't be more clearer.
Also, there is no way to avoid lambdas that have more than one param. The only thing I want is to shorten Function to Fn, and use any sympol to distinguish the return value, and I vote for =>
.
And yes, I want less keystrokes to save a year or tow of my life and a total of a million years or tow of VB programmers lives, along with saving the planet a lot of pollution and waste of resources, both can kill thousands of people due to just few unnecessary keystrokes!
A few keystrokes is understandable as a Microsoft team argument to work less and spend less. But is should not be a programmer's argument by all means!
a practical example:
Lambda-based LinQ:
accounts.UnionWith(TransAcs.
Select(Function(a) a.ToAccount).
Where(Function(a) a.ToAccount.Number > 0)
)
LinQ:
accounts.UnionWith(
From a In TransAcs
Where a.ToAccount.Number > 0
Select a.ToAccount
)
My proposed syntax:
accounts.UnionWith(TransAcs.
Select(.ToAccount).
Where(.ToAccount.Number > 0)
)
LinQ which is less typing than current lambda syntax
LinQ is a bit easier but is never less typing than lambdas syntax!
Really? I literally gave an example in my comment. An example from your original post, and the LINQ-syntax version. Explain to me how the lambda syntax is less typing?
Dim x = items.Select(Function(item) item.Id)
Dim x = From i In items Select i.id
My proposed syntax:
accounts.UnionWith(TransAcs. Select(.ToAccount). Where(.ToAccount.Number > 0) )
So this might work for a LINQ query where there is only one parameter. But lambdas can be used in other scenarios where there is more than one parameter, in which case it won't work, lambdas must work the same wherever they are used.
And what happens if someone puts that inside a With
block?
How would this work alongside with block structures?
LinQ functions expect lambdas, so, no .Member
that belongs to With
will be valid in this context, except as an assigned value:
With Obj
Q.Where(.Name = .Value)
End With
Which can mean:
Q.Where(Function(x) x.Name = Obj.Value
but if the x has a value, then it takes precedence (as happens now when two with interferes:
Q.Where(Function(x) x.Name = x.Value
Currently, this will not break old code, sense no current code can pass just a value to a lambda. In new code, we should follow guidelines not to make such interference.
In fact, I am thinking of another suggestion for a while. I saw a Self
keyword in a programming language called Ring, that refers to the object affecting the inner block, and I think it will be useful in VB in many places, such as here:
With Obj
Q.Where(.Name = Self.Value)
End With
And we discussed before declaring an alias for the with block. I can add another idea:
With Obj
Q.Where(.Name = With.Value)
End With
but practically, self
, the with alias
, and with.
are not that important, as with block is rarely used today. The only critical with is that of anonymous types, and I don't see it possible practically to use linQ inside them, so, we can't have this confliction here.
This another sample I ran into. Here I had to us both Linq and lambdas, as LinQ doesn't have a union keyword:
Dim TransAcs = db.Transfers.Where(
Function(trans) trans.LastEdit = onDate OrElse
trans.Date = onDate)
Return opAcs.Union(feeAcs).
Union(TransAcs.Select(Function(trans) trans.FromAccount)).
Union(TransAcs.Select(Function(trans) trans.ToAccount)).
OrderBy(Function(ac) ac.ID).
Skip(SkipCount).Take(PageSize)
If I wrote it with a dot lambdas:
Dim TransAcs = db.Transfers.Where(
.LastEdit = onDate OrElse trans.Date = onDate)
Return opAcs.Union(feeAcs).
Union(TransAcs.Select(.FromAccount)).
Union(TransAcs.Select(.ToAccount)).
OrderBy(.ID).
Skip(SkipCount).Take(PageSize)
Furthermore, we can compact Union(TransAcs.Select(.FromAccount))
to just Union(TransAcs.FromAccount)
as Select is a default method!
Dim TransAcs = db.Transfers.Where(
.LastEdit = onDate OrElse trans.Date = onDate)
Return opAcs.Union(feeAcs).
Union(TransAcs.FromAccount).
Union(TransAcs.ToAccount).
OrderBy(.ID).
Skip(SkipCount).Take(PageSize)
Suppose we have this list: items = new List(Of (Id As Integer, Text As String)()
I suggest using this short lambda syntax:
Dim x = items.Select(.Id)
instead of this:
Dim x = items.Select(Function(item) item.Id)
More formulas involving other fields are possible:
Dim y = items.Select(.Id & ", " & .Text)
Note that can break old codes that uses With blocks, so, we can use one of two solutions:
For me, I didn't use the
With Block
for 2 decades and I have no problem of choosing either of the above. But if you don't prefer neither, another way of thinking, is to use another notation instead of.
, such as:Dim x = items.Select(:Id)
Dim x = items.Select(@Id)
We already have a familiar alternative that is ready to be put in use, that is the dictionary lockup symbol:
Dim x = items.Select(!Id)
VB lambda syntax is unreasonably too long, and feel bad every time I use them, unlike C#'s:
var x = items.Select(item => item.Id);
which is short but still confusing! I previously suggest an alternative syntax for both languages:x = items.Select(Fn(item) => item.Id)
Which is a compromise between length and readability. II already implemented this ssynatx as a part of my ZML razor syntax. But, I see now that in many situations, we don't even want such whole decoration. We just want to access a field or combine two fields in a direct syntax, so, why can't we shorten lambdas to a dot field result syntax:x = items.Select(.Id)
and let the compiler generate the whole fancy decorated syntax? Fore me,x = items.Select(.Id)
is more readable and understandable than:Dim x = items.Select(Function(item) item.Id)
See this function, which I am using in one of my projects, and forced me to think of a solution:
The part
New ObservableCollection(Of String)(items.Select(Function(item) item.Text))
is not as a vb-style code as should. I wish use the short lambdas like this:New ObservableCollection (Of String)(items.Select(.Text)
And the whole sub becomes:Another thing I asked for, is to allow aliasing tuples and the generic syntax:
For me, this is how a true VB code should appear.