-
Notifications
You must be signed in to change notification settings - Fork 66
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
Block expressions #109
Comments
Using
Dim timeOfWeek = Select Case Date.Today.DayOfWeek
Case DayOfWeek.Monday To DayOfWeek.Friday
"Work Week"
Case DayOfWeek.Saturday, DayOfWeek.Sunday
"Weekend"
End Select or
|
Dropping the {} is another reasonable approach. It means only supporting a single statement, which might be plenty. I'm not sure how I would analyze a large code base to see what benefit, if any, would be gained by such a feature. Maybe looking for cases where Case blocks are just initializing the same variable to different values (rather than doing different things). |
There is an ambiguity in the following code. Function F()
Dim timeOfWeek =
Select Case Date.Today.DayOfWeek
Case DayOfWeek.Monday To DayOfWeek.Friday
Return "Work Week"
Case DayOfWeek.Saturday, DayOfWeek.Sunday
Return "Weekend"
End Select
End Function Is this an error; Incomplement statement |
@AdamSpeight2008 I'm curious, for this new "Block expressions" form of
Would that help out the ambiguities you showed? Also, if that is possible, could this "immediately follows a parenthesis" concept open the door to inline assignments and perhaps other ideas?:
|
If one situation is an error and the other is not it's not an ambiguity. |
Similarly, it's not an issue to use {} because an array literal never could have contained a select case before. When you parse the { you peek one token ahead. If it's a Select it's a block and if not it's an array literal. |
The first would not have compiled, the second would. Hence the breaking change. |
Which is the second? |
First is using current implement (ie no block expression). Second is with. |
Could you paste in the specific code you're talking about. I want to be sure we're talking about the same example. |
Function F()
Dim timeOfWeek =
Select Case Date.Today.DayOfWeek
Case DayOfWeek.Monday To DayOfWeek.Friday
Return "Work Week"
Case DayOfWeek.Saturday, DayOfWeek.Sunday
Return "Weekend"
End Select
End Function |
That code doesn't compile today, with the feature it would compile. This is not a breaking change. It's just a change--a non-breaking change; it's a new feature. Most new features are taking something that didn't compile and making them compile, so in 2005:
Would just be a bunch of parse errors and in 2008 it means something. A breaking change specifically means the program compiled and executed one way in one version and either stopped compiling entirely in the next or compiled and executed differently than before. Since your code example didn't compile and can't execute today it can't be a breaking change. And while there are no ambiguities in the code example (it can only mean the valid parse) it's even clearer in my original proposal specifically because the
The reason the delimiters are valuable is if you want to allow multi-statement blocks:
In this case, it can only work if we require the delimiters or only the first statement would be part of the "block" and the others would not. |
Because the existing usage of Dim timeOfWeek = { Select Case Date.Today.DayOfWeek
Case DayOfWeek.Monday To DayOfWeek.Friday
"Work Week"
Case DayOfWeek.Saturday, DayOfWeek.Sunday
"Weekend"
End Select } is likely to interpreted as roughly equivalent to Dim timeOfWeek As String() = { "Work Week" }
' or
Dim timeOfWeek As String() = { "Weekend" } and not as Dim timeOfWeek As String = "Work Week"
'or
Dim timeOfWeek AS String = "Weekend" Especially confusing when use in multi-dimensional array literals, how many dimensions is it?
Parenthesis usage could cause confusion with Tuple Liteals. I think Function F()
Dim timeOfWeek = _
Select Case Date.Today.DayOfWeek
Case DayOfWeek.Monday To DayOfWeek.Friday
Return "Work Week"
Case DayOfWeek.Saturday, DayOfWeek.Sunday
Return "Weekend"
End Select
End Function |
Wouldn't VB style suggest delimiters using words? ie
|
Crap, I might have accidently proposed adding what we were calling sequence expressions in C# (but ultimately cut) two releases ago to VB. * Goes off to rethink his life * |
@AnthonyDGreen @AdamSpeight2008 @rskar-git @srivatsn @migueldeicaza
But it will be nice to simplify this syntax.. I suggest:
The Evaluate block is a lamda expression with suplied values for its parameters. this aloow us to evaluate any expression not just Select case, and work on any number of variables in the expresion. |
If the Evaluate end Evaluate is not accepted, it can be done by the Function end function keywords, say like this:
|
@AnthonyDGreen Dim timeOfWeek = Get
Select Case Date.Today.DayOfWeek
Case DayOfWeek.Monday To DayOfWeek.Friday
"Work Week"
Case DayOfWeek.Saturday, DayOfWeek.Sunday
"Weekend"
End Select
End Get That is my #398 proposal. And inside XML literals, I see no need to use any block more than the Return <xml>
<%= For Each item in aList
<NodesiNeed fora="<%= item %>" />
Next %>
</xml> This is my #397 proposal. And if we have to use the returned Value in an expression (Which is not mosf likely inside XML literals), then we can use the |
Firstly: Just please no more squiggly brackets (or any other new punctuation). It's bad enough they got used for the initializer's On its own, SELECT returning a value, like SQL's CASE, has merit, but I can see it being abused, and (IMHO) anything more complicated than the examples in this thread would probably be better served by using a discrete method, for which local functions (which have cropped up elsewhere in this forum recently) might be more legible than an monster block expression. To ensure my dead horse remains flogged: I don't think VB as a language is improved by programming shortcuts introduced for the sake of saving a few keystrokes during development (which this looks a bit like), if the end result is more difficult for the maintainer of the software five years later after you've left the company. And as @AnthonyDGreen said in his opening comment:
That's a language paradigm choice, changing that changes the language into a new language. |
I'm fine with using a keyword instead of curly braces, but how would this work for continuing the expression? 'This works pretty well...
Dim nextId = {
'Get last ID
Dim lastRecord = database.GetLastRecord()
Dim lastId = lastRecord.Id
Return lastId
} + 1
'This works less...
Dim nextId = Get
'Get last ID
Dim lastRecord = database.GetLastRecord()
Dim lastId = lastRecord.Id
Return lastId
End Get + 1 'what?? Or do we say that using doing any other processing along with an expression block is using an anti-pattern? |
Yes. |
@pricerc: I don't want a select expression to save characters, I want a select expression to increase readability. If I have = |
I understand that, which is why I said:
I don't know why my last response was quite so terse. Let me expand on it.
Yes. I'd argue that this pattern works better: Function GetNextID() As ID
Dim lastRecord = database.GetLastRecord()
Dim lastId = lastRecord.Id
Return lastId
End Function
....
Dim nextId = GetNextID() Where GetNextID could be a local function, which I like the idea of and I think would be a better solution than the anonymous functions that block expressions are necessarily converted into by the compiler. |
@pricerc Fair enough, and I agree in the specific example mentioned above. I was just throwing out the question of whether there's EVER a legitimate use of block expressions within another expression, or whether that's ALWAYS an anti-pattern.
@pricerc Again, I agree with you in this specific case, but I just want to point out that
|
I don't know that I'd commit to ALWAYS, because in my life's experience, there are always exceptions to prove a rule.
To be fair, I don't go hunting for them, but I've yet to see an example of an anonymous function where its readability would be reduced by refactoring it out into a named method. I'd say at best anonymous function have nil effect on readability, but never inherently positive. But I do concede this to be subjective, and don't judge people for using them :).
I would think that would depend on the complexity of the block. It certainly introduces a new scope, which needs to be managed and potentially debugged. |
I have another approach for this: Dim y = Select case x
case 1
Me.Return "Once"
case 2
Me.Return "Twice"
case else
Me.Return "Many Times"
End Select Do
' some code
If Not (Do
' some code
If someCondition Then Me.Return false
Loop) Then Exit Do
Loop Notes:
|
@VBAndCs Me is for the current instance of a class. Any other use I would call a 'bad idea'. And if you were going to do that much Returning, you may as well just use a function. |
This proposal combined with @AnthonyDGreen 's Top-Level Code Prototype can achieve this proposal like this: Dim timeOfWeek = <( Select Case Date.Today.DayOfWeek
Case DayOfWeek.Monday To DayOfWeek.Friday
"Work Week"
Case DayOfWeek.Saturday, DayOfWeek.Sunday
"Weekend"
End Select )> and many more, like embedding code in interpolated strings Dim Msg= $" time Of Week is {<( Select Case Date.Today.DayOfWeek
Case DayOfWeek.Monday To DayOfWeek.Friday
"Work Week"
Case DayOfWeek.Saturday, DayOfWeek.Sunday
"Weekend"
End Select )>}" |
VB is a statement oriented language but sometimes a computation is difficult to express purely expressions. We've attacked this problem before with the
If
expression but that's always left open the question of whether we should do it forSelect Case
too. T-SQL has aCASE
expression and the topic has been raised again when considering whether an expression form of pattern matching would be needed.I'm not a big fan of creating a new expression based syntax for everything and I do think preferring statements is more readable. That said, it's worth considering what a potential design would do to the language. Taking a cue from piecewise function notation this proposal is using
{
and}
to delineate a statement block. Believe it or not but there are surprisingly few ambiguities with these characters. The minimal feature we could consider would beSelect Case
:It seems straight-forward enough what's happening, maybe? It also solves the problem some languages solve with a
Let
statement and would avoid adding a specificSelect Case
orMatch
expression.Should we have a special keyword for yielding the ultimate value of the expression (e.g.
Yield
). I suspectReturn
wouldn't be ambiguous (since today it can't appear in the middle of an expression) but it could be confusing. What if instead we take a page from the F# manual and say that the value of the block is the value of the last expression statement along an execution path.That's
Select Case
but if we do that what if we redidIf
? It would solve scenario #97 without changing the behavior of theIf
expression:Dim b As Boolean? = { If crmDate.IsNull Then Nothing Else crmDate.Value }
Inspired by #57 what if we supported more than just
Select Case
andIf
, what if we supported loops?That's pretty nice looking, I think. Of course, in this case a loop statement would yield and IEnumerable instead of a single value. Is that too subtle? (YES!) What if we required the Yield statement to create an IEnumerable? And maybe we could even just do more statements if we can work out ambiguities.
The reason this could work without syntactic ambiguity is because every executable statement in Visual Basic begins with a keyword with the exception of invocation and assignment which may begin with an identifier, and labels which may begin with an identifier or number so the parser can tell pretty quickly if the curlies contain a statement list or an expression list.
Needs a prototype and we need to see code where this would make the code more readable to determine whether this would make VB more expressive without sacrificing straight-forwardness.
The text was updated successfully, but these errors were encountered: