Open AnthonyDGreen opened 7 years ago
So just to be clear, if I may paraphrase this proposal:
In regards to the overload resolution process of the inline If() when either expressionIfTrue or expressionIfFalse is Nothing
, the future design of the compiler's expression parsing routines should also include for consideration the data type of the destination variable. (Should that include the data type of a parameter of a Function
/Sub
call too?).
In the case of duck-typing or any other situation where the data type of the destination is unknown or not applicable, the rules of overload resolution then fall-back to as they currently are (i.e. data type of the destination isn't considered in the resolution process).
With this change in effect, this:
Dim x As Boolean? = If(False, 1, Nothing)
...would be equivalent to:
Dim x As Boolean? = (Function(condition As Boolean) As Boolean?
If condition Then
Return 1
Else
Return Nothing
End If
End Function)(False)
Or in more generic terms, this:
Dim v as T = If(<condition>, <expressionIfTrue>, <expressionIfFalse>)
...is equivalent to:
Dim v As T = (Function(condition As Boolean) As T
If condition Then
Return <expressionIfTrue>
Else
Return <expressionIfFalse>
End If
End Function)(<condition>)
...but only if either <expressionIfTrue>
or <expressionIfFalse>
is Nothing
.
Am I understanding it right?
This is not a proposal. It's a scenario. It just states that there is a problem. There is at least one proposal which I've created a stub issue for (#98) but there may be others. It's not really an overload resolution or parsing related issue. Today the type of the If expression is either the dominant type of the second and third operands or if one cannot be determined object. The entire value of the If
expression is then converted to the destination type. #98 just proposes that that conversion happen sooner.
For example, If I write this today in VB:
Dim strings As String() = {1, 2, 3}
It is not the equivalent of saying:
Dim strings As String() = CType({1, 2, 3}, String())
That cast won't compile because an Integer array cannot be converted to a string array. Instead that code is the equivalent of this:
Dim strings As String() = {CStr(1), CStr(2), CStr(3)}
The conversion is pushed "inside" the array so that the actual type of the array is String(), not Integer(). Another example would be:
Dim strings As Action() = {AddressOf Console.WriteLine}
This only works because the conversion of the AddressOf happens inside of the array.
Dim strings As Action() = {CType(AddressOf Console.WriteLine, Action)}
If it worked the other way it wouldn't compile because an AddressOf has no type and therefore you can't make an array of them.
Dim x As Boolean? = If(False, 1, Nothing)
Being the equivalent of:
Dim x As Boolean? = CType(If(False, 1, CInt(Nothing)), Boolean?)
It'll be the equivalent of:
Dim x As Boolean? = If(False, CType(1, Boolean?), CType(Nothing, Boolean?))
^^ above clarification is most fascinating.
@AnthonyDGreen This one doesn't compile, I think it should.
Dim f As Func(Of FormattableString) = Function() If(True, $"Inherits {y}", $"")
@AdamSpeight2008 Brilliant example!
The formattable string example isn't peculiar to If expressions. eg:
Dim f As Func(Of FormattableString) = Function() $"formattable"
will fail to compile. I'm guessing this is more to do with the IDE wanting to wrap interpolated strings and expose them as string.
Something terrible has happened if that doesn't compile, Bill.
And that's a terrible bug. \<profuse swearing>
For example this works fine:
Dim f As Func(Of FormattableString()) = Function() {$"{1:C02}"}
I'll go file a bug :(
Visual Basic has several "typeless" expressions whose final value depends on target type information:
Nothing
literalAddressOf
expressionsAddressOf
expressions don't have a type. Target-typing allows overload resolution to pick the correct method and instantiate a delegate referring to that method.In the code above the same text,
Function() True
, may have an anonymous delegate type<Function() As Integer>
, named delegate typeFunc(Of Boolean)
, or may produce an expression tree based on target type context.The code above does not first produce an Integer array then convert it to a Byte array; that's impossible. Instead the array literal is always realized as a Byte array and its elements are each converted to Byte.
Because the conditional 'If' operator doesn't propagate target type context into its operands these expressions may be reclassified incorrectly producing programs with subtle bugs or which fail at run-time.
This makes the simple refactoring of an
If
block into anIf
expression dangerous. Additionally, each time we consider adding more target-typed expressions we compound this issue.Examples of programs failing to compile or compiling with surprising behavior.
Similar "common-type" examples can be made whenever both operands are typeless.