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

[T(Index) Is Nothing] is [CObj(T(Index)) Is Nothing] instead [T(Index) Is Default]. #605

Open
RevensofT opened this issue Jul 27, 2021 · 5 comments

Comments

@RevensofT
Copy link

RevensofT commented Jul 27, 2021

    Public Function empty_index(Of T)(Host As T()) As Long
        Dim Length = Host.LongLength,
            Pos = 0L
        Do
            If Pos >= Length Then Return -1

            'Not work with value type.
            If Host(Pos) Is Nothing Then Return Pos

            'Because it's compile to this.
            If CObj(Host(Pos)) Is Nothing Then Return Pos

            'While this work well with value type and reference type.
            If Object.Equals(Input, CType(Nothing, T)) Then Return Pos

            Pos += 1
        Loop
    End Function

Why not Object.Equals ?

Simple answer is super cut corner for performance as you see in IL code below.

ldarg.0
ldloc.2
conv.i4
ldelem     !!T
box        !!T
// call       bool [System.Runtime]System.Object::Equals(object,object)
brtrue.s   IL_0023

Instead call Object.Equals it use 0 aka null pointer compare result so when brtrue which is branch on true and true in this case is anything except 0.

How to fixed it ?

Just reverse back to use Object.Equals.

    <Extension>
    Public Function is_default(Of T)(Input As T) As Boolean
        Return Object.Equals(Input, CType(Nothing, T))
    End Function

Or double down it, cut more corner.

    .method public static bool is_default<T>(!!T Input) cil managed
    {
        .custom instance void [System.Runtime]System.Runtime.CompilerServices.ExtensionAttribute::.ctor() = ( 01 00 00 00 )
        .maxstack  2

        ldarg.0 
        ldc.i4.0 
        ceq 
        ret
    }
@rskar-git
Copy link

There is nothing to be fixed. What you really want is a proper "Is Default" test - something that can tell us if a reference or value-type expression is just all of its bits set to 0. That's what "default" means, in the .NET sense. All 0's is a null for a reference type or a zero for (typical) numeric types or what the default of any given Structure will be.

@RevensofT
Copy link
Author

@rskar-git , How would you check is value of generic type is default in VB.Net ? Is in VB.net can check reference type only and Default only use with Property, Nothing in VB.net is default value of type but in this case we can't use Is or = to check it that why it become problem and we have to fixed this to get result.

Compiler programmer is box !!T to fixed it but not solve all problem, when it is reference type it work fine because boxing null reference will return null reference back but when its type is value type, boxing it won't return null reference or default of those type back instead it will return boxed of value which not count as null reference or 0 so it make VB.net can't check default value of generic type normally via language feature so I need to fixed by use Object.Equals(Input, CType(Nothing, T)) or cut more corner in IL code.

@rskar-git
Copy link

How would you check is value of generic type is default in VB.Net ? ...

For an unconstrained T, where you want the position of a null for references or default for value-types or default of a value-type boxed as an Object, then maybe:

Function empty_index(Of T)(Host As T()) As Long

    Dim Length = Host.LongLength,
                Pos = 0
    Do
        If Pos >= Length Then Return -1

        If GetType(T).IsValueType Then
            If Host(Pos).Equals(DirectCast(Nothing, T)) Then Return Pos
        Else
            If Host(Pos) Is Nothing Then Return Pos
            If Host(Pos).GetType().IsValueType Then
                If Host(Pos).Equals(DirectCast(Nothing, T)) Then Return Pos
            End If
        End If

        Pos += 1
    Loop

End Function

@RevensofT
Copy link
Author

RevensofT commented Jul 29, 2021

With so many if and type access info I think those cut corner won't make it better then just use Object.Equals; anyway it sad to see VB.net language syntax can't even to keep up very old feature like generic type, I feel like many old syntax still stuck in .Net 2.0 era.

@rskar-git
Copy link

Nicer code:

Function empty_index(Of T)(Host As T()) As Long

    Dim Length = Host.LongLength,
                Pos = 0
    Do
        If Pos >= Length Then Return -1

        If EqualityComparer(Of T).Default.Equals(Host(Pos), Nothing) Then
            ' See https://stackoverflow.com/questions/65351/null-or-default-comparison-of-generic-argument-in-c-sharp
            Return Pos
        End If

        Pos += 1
    Loop

End Function

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants