Skip to content
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

[Proposal] Make ?? pattern-based for struct left-hand-side #4347

Closed
orthoxerox opened this issue Aug 5, 2015 · 10 comments
Closed

[Proposal] Make ?? pattern-based for struct left-hand-side #4347

orthoxerox opened this issue Aug 5, 2015 · 10 comments
Assignees
Labels
Area-Language Design Resolution-Won't Fix A real bug, but Triage feels that the issue is not impactful enough to spend time on.

Comments

@orthoxerox
Copy link
Contributor

Right now ?? can only be used with reference types or Nullable T value types. Could it be amended so it works with all structs that have bool HasValue and T GetValueOrDefault?

@svick
Copy link
Contributor

svick commented Aug 5, 2015

Why? In what situations would that be useful? Why do you think such situations happen often enough for this change to be worth it?

@orthoxerox
Copy link
Contributor Author

Right now we cannot replace Nullable T with a better custom alternative and keep using existing syntax, while LINQ, for example, works for any object that implements LINQ methods.

@svick
Copy link
Contributor

svick commented Aug 5, 2015

Why would you need a "better custom alternative" to Nullable<T>? If you have good suggestions, wouldn't it make sense to propose improving Nullable<T> instead of trying to work around the issue?

@paul1956
Copy link
Contributor

paul1956 commented Aug 5, 2015

QuickBooks SDK API for example is defined around HasValue which needs to be checked before reading the value.

Sent from my iPhone
I apologize for any typos Siri might have made.
(503) 803-6077

On Aug 5, 2015, at 5:00 AM, Petr Onderka [email protected] wrote:

Why would you need a "better custom alternative" to Nullable? If you have good suggestions, wouldn't it make sense to propose improving Nullable instead of trying to work around the issue?


Reply to this email directly or view it on GitHub.

@codespare
Copy link
Contributor

yes, but imagine tailoring the language to every api? that could quickly grind C# new features development to a halt.
besides https://msdn.microsoft.com/en-us/library/2b314yt2(v=vs.100).aspx
looks it works already with xsd.exe run on intuit xsd schemas elements, just add a nillable="true" attribute, and you'll have Nullable properties, and databinding support.
(json and the intuit rest api, xsd2cs or even forking Roslyn to try out what you want to achieve could also be worth a try)

@paul1956
Copy link
Contributor

paul1956 commented Aug 5, 2015

Already solved the problem but I don't see how to use null coalescing.

I have lots of code that look like
If x is Nothing OrElse x.hasValue = False OrElse x.getstring.lenght = 0 then return string.empty

Not sure how to convert this to take advantage of current feature.

Sent from my iPhone
I apologize for any typos Siri might have made.
(503) 803-6077

On Aug 5, 2015, at 11:53 AM, codespare [email protected] wrote:

yes, but imagine tailoring the language to every api? that could quickly grind C# new features development to a halt.
besides https://msdn.microsoft.com/en-us/library/2b314yt2(v=vs.100).aspx
looks it works already with xsd.exe run on intuit xsd schemas elements, just add a nillable="true" attribute, and you'll have Nullable properties, and databinding support.
(json and the intuit rest api, xsd2cs or even forking Roslyn to try out what you want to achieve could also be worth a try)


Reply to this email directly or view it on GitHub.

@codespare
Copy link
Contributor

The simplest approach depends on what you can modify. Above, I assume you are using the API as documented https://developer.intuit.com/docs/0100_accounting with XML messages over HTTP, in which case xsd.exe generates the following (shortened) type from https://developer.intuit.com/docs/@api/deki/files/54/bankingaccount_1.xsd:

Option Strict Off
Option Explicit On

Imports System.Xml.Serialization

'
'This source code was auto-generated by xsd, Version=4.6.81.0.
'

'''<remarks/>
<System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.6.81.0"),  _
 System.SerializableAttribute(),  _
 System.Diagnostics.DebuggerStepThroughAttribute(),  _
 System.ComponentModel.DesignerCategoryAttribute("code"),  _
 System.Xml.Serialization.XmlTypeAttribute(AnonymousType:=true, [Namespace]:="http://schema.intuit.com/platform/fdatafeed/bankingaccount/v1"),  _
 System.Xml.Serialization.XmlRootAttribute([Namespace]:="http://schema.intuit.com/platform/fdatafeed/bankingaccount/v1", IsNullable:=false)>  _
Partial Public Class BankingAccount
    Inherits Object
    Implements System.ComponentModel.INotifyPropertyChanged

    Private bankingAccountTypeField As System.Nullable(Of BankingAccountType)

    Private bankingAccountTypeFieldSpecified As Boolean

    Private postedDateField As System.Nullable(Of Date)

    Private postedDateFieldSpecified As Boolean

    Private availableBalanceAmountField As System.Nullable(Of Decimal)

    Private availableBalanceAmountFieldSpecified As Boolean

    Private interestTypeField As String

    '''<remarks/>
    <System.Xml.Serialization.XmlElementAttribute(IsNullable:=true)>  _
    Public Property bankingAccountType() As System.Nullable(Of BankingAccountType)
        Get
            Return Me.bankingAccountTypeField
        End Get
        Set
            Me.bankingAccountTypeField = value
            Me.RaisePropertyChanged("bankingAccountType")
        End Set
    End Property

    '''<remarks/>
    <System.Xml.Serialization.XmlIgnoreAttribute()>  _
    Public Property bankingAccountTypeSpecified() As Boolean
        Get
            Return Me.bankingAccountTypeFieldSpecified
        End Get
        Set
            Me.bankingAccountTypeFieldSpecified = value
            Me.RaisePropertyChanged("bankingAccountTypeSpecified")
        End Set
    End Property

    '''<remarks/>
    <System.Xml.Serialization.XmlElementAttribute(IsNullable:=true)>  _
    Public Property postedDate() As System.Nullable(Of Date)
        Get
            Return Me.postedDateField
        End Get
        Set
            Me.postedDateField = value
            Me.RaisePropertyChanged("postedDate")
        End Set
    End Property

    '''<remarks/>
    <System.Xml.Serialization.XmlIgnoreAttribute()>  _
    Public Property postedDateSpecified() As Boolean
        Get
            Return Me.postedDateFieldSpecified
        End Get
        Set
            Me.postedDateFieldSpecified = value
            Me.RaisePropertyChanged("postedDateSpecified")
        End Set
    End Property

    '''<remarks/>
    <System.Xml.Serialization.XmlElementAttribute(IsNullable:=true)>  _
    Public Property availableBalanceAmount() As System.Nullable(Of Decimal)
        Get
            Return Me.availableBalanceAmountField
        End Get
        Set
            Me.availableBalanceAmountField = value
            Me.RaisePropertyChanged("availableBalanceAmount")
        End Set
    End Property

    '''<remarks/>
    <System.Xml.Serialization.XmlIgnoreAttribute()>  _
    Public Property availableBalanceAmountSpecified() As Boolean
        Get
            Return Me.availableBalanceAmountFieldSpecified
        End Get
        Set
            Me.availableBalanceAmountFieldSpecified = value
            Me.RaisePropertyChanged("availableBalanceAmountSpecified")
        End Set
    End Property

    '''<remarks/>
    <System.Xml.Serialization.XmlElementAttribute(IsNullable:=true)>  _
    Public Property interestType() As String
        Get
            Return Me.interestTypeField
        End Get
        Set
            Me.interestTypeField = value
            Me.RaisePropertyChanged("interestType")
        End Set
    End Property

    Public Event PropertyChanged As System.ComponentModel.PropertyChangedEventHandler Implements System.ComponentModel.INotifyPropertyChanged.PropertyChanged

    Protected Sub RaisePropertyChanged(ByVal propertyName As String)
        Dim propertyChanged As System.ComponentModel.PropertyChangedEventHandler = Me.PropertyChangedEvent
        If (Not (propertyChanged) Is Nothing) Then
            propertyChanged(Me, New System.ComponentModel.PropertyChangedEventArgs(propertyName))
        End If
    End Sub
End Class

'''<remarks/>
<System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.6.81.0"),  _
 System.SerializableAttribute(),  _
 System.Xml.Serialization.XmlTypeAttribute([Namespace]:="http://schema.intuit.com/platform/fdatafeed/bankingaccount/v1")>  _
Public Enum BankingAccountType

    '''<remarks/>
    CHECKING

    '''<remarks/>
    SAVINGS

    '''<remarks/>
    MONEYMRKT

    '''<remarks/>
    RECURRINGDEPOSIT

    '''<remarks/>
    CD

    '''<remarks/>
    CASHMANAGEMENT

    '''<remarks/>
    OVERDRAFT
End Enum

which supports null coalescing:

    Sub Foo(acc As BankingAccount)
        Dim interestType = If(acc.interestType, "none")
    End Sub

The specifics you are after likely differ from that very example, but looking for a fix upstream in the chain to end up with a more usable API surface is quite generic. And in the case of a web service API and code generation, you can often achieve improvements without modifying the language and compiler. In your example, that would be in the definition of 'x' type and its properties.

@paul1956
Copy link
Contributor

paul1956 commented Aug 6, 2015

I am using the interop libraries, don't know how they were generated but your example is something I will look into.

My question was more generic. In a typical case I want to check x for Nothing and if not Nothing check a x.method for valid value. It appears the "else" part is where my return goes (or I need to use Not).

Unless I am misunderstanding how this works I guess invertIf will be a very popular refactoring.

If x?.age>0 then
Else
Return 0
End if

Sent from my iPhone
I apologize for any typos Siri might have made.
(503) 803-6077

On Aug 6, 2015, at 6:05 AM, codespare [email protected] wrote:

The simplest approach depends on what you can modify. Above, I assume you are using the API as documented https://developer.intuit.com/docs/0100_accounting with XML messages over HTTP, in which case xsd.exe generates the following (shortened) type from https://developer.intuit.com/docs/@api/deki/files/54/bankingaccount_1.xsd:

Option Strict Off
Option Explicit On

Imports System.Xml.Serialization

'
'This source code was auto-generated by xsd, Version=4.6.81.0.
'

'''
<System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.6.81.0"), _
System.SerializableAttribute(), _
System.Diagnostics.DebuggerStepThroughAttribute(), _
System.ComponentModel.DesignerCategoryAttribute("code"), _
System.Xml.Serialization.XmlTypeAttribute(AnonymousType:=true, [Namespace]:="http://schema.intuit.com/platform/fdatafeed/bankingaccount/v1"), _
System.Xml.Serialization.XmlRootAttribute([Namespace]:="http://schema.intuit.com/platform/fdatafeed/bankingaccount/v1", IsNullable:=false)> _
Partial Public Class BankingAccount
Inherits Object
Implements System.ComponentModel.INotifyPropertyChanged

Private bankingAccountTypeField As System.Nullable(Of BankingAccountType)

Private bankingAccountTypeFieldSpecified As Boolean

Private postedDateField As System.Nullable(Of Date)

Private postedDateFieldSpecified As Boolean

Private availableBalanceAmountField As System.Nullable(Of Decimal)

Private availableBalanceAmountFieldSpecified As Boolean

Private interestTypeField As String

'''<remarks/>
<System.Xml.Serialization.XmlElementAttribute(IsNullable:=true)>  _
Public Property bankingAccountType() As System.Nullable(Of BankingAccountType)
    Get
        Return Me.bankingAccountTypeField
    End Get
    Set
        Me.bankingAccountTypeField = value
        Me.RaisePropertyChanged("bankingAccountType")
    End Set
End Property

'''<remarks/>
<System.Xml.Serialization.XmlIgnoreAttribute()>  _
Public Property bankingAccountTypeSpecified() As Boolean
    Get
        Return Me.bankingAccountTypeFieldSpecified
    End Get
    Set
        Me.bankingAccountTypeFieldSpecified = value
        Me.RaisePropertyChanged("bankingAccountTypeSpecified")
    End Set
End Property

'''<remarks/>
<System.Xml.Serialization.XmlElementAttribute(IsNullable:=true)>  _
Public Property postedDate() As System.Nullable(Of Date)
    Get
        Return Me.postedDateField
    End Get
    Set
        Me.postedDateField = value
        Me.RaisePropertyChanged("postedDate")
    End Set
End Property

'''<remarks/>
<System.Xml.Serialization.XmlIgnoreAttribute()>  _
Public Property postedDateSpecified() As Boolean
    Get
        Return Me.postedDateFieldSpecified
    End Get
    Set
        Me.postedDateFieldSpecified = value
        Me.RaisePropertyChanged("postedDateSpecified")
    End Set
End Property

'''<remarks/>
<System.Xml.Serialization.XmlElementAttribute(IsNullable:=true)>  _
Public Property availableBalanceAmount() As System.Nullable(Of Decimal)
    Get
        Return Me.availableBalanceAmountField
    End Get
    Set
        Me.availableBalanceAmountField = value
        Me.RaisePropertyChanged("availableBalanceAmount")
    End Set
End Property

'''<remarks/>
<System.Xml.Serialization.XmlIgnoreAttribute()>  _
Public Property availableBalanceAmountSpecified() As Boolean
    Get
        Return Me.availableBalanceAmountFieldSpecified
    End Get
    Set
        Me.availableBalanceAmountFieldSpecified = value
        Me.RaisePropertyChanged("availableBalanceAmountSpecified")
    End Set
End Property

'''<remarks/>
<System.Xml.Serialization.XmlElementAttribute(IsNullable:=true)>  _
Public Property interestType() As String
    Get
        Return Me.interestTypeField
    End Get
    Set
        Me.interestTypeField = value
        Me.RaisePropertyChanged("interestType")
    End Set
End Property

Public Event PropertyChanged As System.ComponentModel.PropertyChangedEventHandler Implements System.ComponentModel.INotifyPropertyChanged.PropertyChanged

Protected Sub RaisePropertyChanged(ByVal propertyName As String)
    Dim propertyChanged As System.ComponentModel.PropertyChangedEventHandler = Me.PropertyChangedEvent
    If (Not (propertyChanged) Is Nothing) Then
        propertyChanged(Me, New System.ComponentModel.PropertyChangedEventArgs(propertyName))
    End If
End Sub

End Class

'''
<System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.6.81.0"), _
System.SerializableAttribute(), _
System.Xml.Serialization.XmlTypeAttribute([Namespace]:="http://schema.intuit.com/platform/fdatafeed/bankingaccount/v1")> _
Public Enum BankingAccountType

'''<remarks/>
CHECKING

'''<remarks/>
SAVINGS

'''<remarks/>
MONEYMRKT

'''<remarks/>
RECURRINGDEPOSIT

'''<remarks/>
CD

'''<remarks/>
CASHMANAGEMENT

'''<remarks/>
OVERDRAFT

End Enum
which supports null coalescing:

Sub Foo(acc As BankingAccount)
    Dim interestType = If(acc.interestType, "none")
End Sub

The specifics you are after likely differ from that very example, but looking for a fix upstream in the chain to end up with a more usable API surface is quite generic. And in the case of a web service API and code generation, you can often achieve improvements without modifying the language and compiler. In your example, that would be in the definition of 'x' type and its properties.


Reply to this email directly or view it on GitHub.

@lassevk
Copy link

lassevk commented Aug 7, 2015

This would make it work with a "Option" type value as well.

@gafter gafter changed the title Please unlink null coalescing operator from Nullable T [Proposal] Make ?? pattern-based for struct left-hand-side Aug 16, 2015
@gafter gafter added this to the C# 7 and VB 15 milestone Aug 16, 2015
@gafter gafter self-assigned this Aug 16, 2015
@gafter
Copy link
Member

gafter commented Oct 5, 2015

We've decided not to do this. The ?? operator isn't the only thing that we do specially for Nullable<T>, and supporting all of the relevant operators would be a complex design exercise for little gain.

@gafter gafter closed this as completed Oct 5, 2015
@gafter gafter added the Resolution-Won't Fix A real bug, but Triage feels that the issue is not impactful enough to spend time on. label Oct 5, 2015
@gafter gafter modified the milestone: C# 7 and VB 15 Nov 26, 2015
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area-Language Design Resolution-Won't Fix A real bug, but Triage feels that the issue is not impactful enough to spend time on.
Projects
None yet
Development

No branches or pull requests

7 participants