Comments (6)
@jrmoreno1
Any checks if the collection has any members. It is a Boolean method and you can't call any other method from it. This is how you should write your code:
If ids?.Any() Then
Console.WriteLine(ids.First)
End If
Or directly:
Console.WriteLine(ids?.FirstOrDefault)
from vblang.
Hey @jrmoreno1,
I'm pretty sure I was the language PM when this feature was implemented (or soon thereafter). The behavior you're describing is confusing and the behavior you want makes perfect sense in the exact scenario you're describing. I can't change it but perhaps I can provide some context as to why it behaves as it does by design.
First, it's important to point out the the way ?.
behaves is determined syntactically, not semantically. That is to say the behavior of a?.b.c()
is decided without regard to whether b
is a property or a function or returns Boolean
or Integer
or a nullable type like String
. So when you say "when used in conjunction with a boolean function" that's not how the feature is designed (regardless of whether it should have been).
Second, as to how it is designed--we had a very heated debate when implementing this feature in both VB and C# as to whether the feature would be left-associative or right-associative, i.e. whether a?.b.c.d.e.f
would mean (a?.b).c.d.e.f
or (made up syntax) a?(.b.c.d.e.f)
. This is a question of how the syntax is parsed and that impacts how its meaning is determined.
Your original post appears to be requesting that for Boolean functions specifically, ?.
be parsed or at least interpreted left-associatively. First, I'll try to explain why we didn't make it left-associatively for all functions/members and then we can discuss whether an exception for booleans is reasonable/possible.
Given the expression id?.First().ToString()
if ids
is null, left-associative (null?.First()).ToString()
would throw an exception. In order to get the current (and likely more desired behavior of safety) one would need to type ids?.First()?.ToString()
. In fact, for any expression a?,b,c,d,e,f
an exception would be thrown if a
is null. The feature would be near useless unless you always typed a?.b?.c?.d?.e?.f
. That would be the only safe code.
Interestingly enough, the members of Nullable(Of T)
(and, I suppose an extension method which tolerates a null receiver) are literally the only members that are useful to call off of (a?.b)
in the case that a
is null. Any other member invocation would throw an exception.
Now for value types this isn't that bad because the members if T?
aren't the same as the members of T
, which is your situation. IntelliSense would naturally lead you to know that the left-associative behavior of a?.b.c
was unsafe. But for reference types it would be invisible and just blow up at runtime. We felt that was kinda useless so we made the feature do what it does now where you only need to use ?.
immediately to the right of a thing which you expect could be null.
So back to your specific exception: Boolean functions. Booleans tend to be terminal in member access chains--if .M()
returns a Boolean
there isn't like to be a .M().Anything
. In fact that's probably true of most of the primitive value types other than Date
because Date
has subparts like .Hour/Minute/Second
. i.e. I would think your request makes as much sense for If ids?.Count().GetValueOrDefault() Then
as well even though Count
returns an Integer
and not for If dates?.First().IsDaylightSavingTime Then
because dates?.First()
returns a Date
. Hopefully, you agree that toggling the behavior of the feature on whether a?.b()
returns an Integer
, Boolean
, or Date
is ... messy.
All of that being said, I agree your situation sucks. I think the reason is that most of what we consider a person will do with nullable result of a ?.
expression naturally obviates the need for parentheses. Using a binary operator like a comparison (sorta) does what you'd want and using the "null coalescing" operator If(ids?.Any(), False)
would naturally work. Except no one in their right mind would ever write If If(ids?.Any(), False) Then
and therein lies the problem. If the syntax had been If ids?.Any() ?? False Then
you would be fine. Already, If ids?.Any() Is Nothing Then
reads and writes fine (though it's not particularly helpful). I suspect we've forced you to use GetValueOrDefault() and that's why you're here (I could be wrong).
That's a lot of words to say, the team almost certainly can't (and won't) do what you're asking. I tried to provide some context of how we got here. Now all I can do is try to think of ways to help you and others that fall into this unfortunate ditch on the side of the road (in my next comment).
from vblang.
@VBAndCs : I know how to make it work, I am saying that how it works is wrong. Any returns a Boolean, ?.Any returns a nullable Boolean, nullable booleans should not require parentheses in order to work.
from vblang.
@jrmoreno1
the .Any
method returns a Boolean, and the dot belongs to it:
If ids?.Any().CompareTo(False) = 1 Then
Console.WriteLine("OK")
End If
If (ids?.Any().CompareTo(False)).GetValueOrDefault() = 1 Then
Console.WriteLine("OK")
End If
from vblang.
OK, so:
- Introducing
??
to VB is out. MSFT isn't adding new syntax to VB and even if they were it's dubious just adding a new syntax that does the same thing (this is perhaps the only syntax in the whole of C# that I envy). - One could imagine a tooling fix wherein when you type
If ids?.Any().
the IDE shows members of both whateverAny()
returns and the members of nullable of whateverAny()
returns only if you pick on of the members ofNullable
you get an error telling you to parenthesize the whole expression. - Option 2 by itself is stupid and I only wrote it as a necessary step to Option 3, which would be to do the same thing but if you select a member of nullable, when you commit the line the IDE automatically parenthesizes the expression
ids?.Any()
for you, which wouldn't be pretty like you want but wouldn't leave others confused and would still be a nice typing experience, I think. This is similar to the experience in the IDE today which lets you pick extension members which are not in scope only to add the necessaryImports
statement to your file if you select them.
I personally like Option 3 as a compromise. Not sure if the IDE would accept a PR doing this, and no one has volunteered to do the work, and I also don't know if you find it acceptable. I find a lot of language/tooling decisions I think about lately to fall into a "don't want to have to say it" vs "don't want to have to see it" dichotomy. My solution addressing having to say the parentheses though your original post suggests you don't want to see them either and there just isn't anything to be done about that at this point :(
Warmest regards,
-ADG
from vblang.
@AnthonyDGreen : I used Boolean, simply because that was where I was encountering it, and it seems especially egregious. Thanks for the explanation, it does make sense, and a primitive could have a ToString after it…so even they wouldn’t necessarily be the end of the chain. I generally find If(a,b) at least as good as ??, but this is definitely an exception. I have done some analyzers / code fixes but not for a while and not much. I’ll have to check to see if just parentheses does what I want….
from vblang.
Related Issues (20)
- [Proposal] Additional Kinds of Is Clauses
- (off-topic?) inter-language 'drag race' competition HOT 20
- [Proposal] Tuple Sub-Clauses
- Support unmanaged generic constraint for interop with C#
- [T(Index) Is Nothing] is [CObj(T(Index)) Is Nothing] instead [T(Index) Is Default]. HOT 5
- Discard XML namespaces HOT 2
- Strange “type of” HOT 3
- ByRef Me for Structure HOT 3
- Record method for My.Computer.Audio HOT 3
- Custom implicit Ctype is not used in dynamic mode HOT 4
- [Proposal] ReadOnly As InitOnly Properties
- "Two Anxieties and One Unarticulated Need - Why doing nothing is sometimes the right thing to do" -- Anthony D. Green HOT 5
- "An Alternative Path" HOT 2
- Open Silver Roadmap: VB.Net support HOT 1
- VB to support consuming API that has required members. HOT 3
- Open Letter on the Visual Basic Strategy 2023 HOT 34
- CDate(CStr(Nothing)) should not cause an exception HOT 5
- 请支持vb,please support vb HOT 10
- Small Visual Basic is meant to attract kids to VB .NET HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from vblang.