3

I want to do some arithmetic addition in my generic class with some constraints in place. For brevity, assume there is just one public member named Value.

Public MustInherit Class GenericInterval(Of T As {Structure, IComparable})
    Public Value As T

    '(1) filled in below
End Class

Outside the class, I have an interface and a structure implementing it as follows:

Public Interface IAddable(Of U As {Structure, IComparable})
    Function Add(a As U, b As U) As U
End Interface

Public Structure Int64Calculator
    Implements IAddable(Of Int64)

    Public Function Add(ByVal a As Int64, ByVal b As Int64) As Int64 _
        Implements IAddable(Of Int64).Add
        Return a + b
    End Function
End Structure

This enables me to create a function in my class at position marked (1) above. There are some constraints, but as far as I can tell, I think I got that part right. New on C is needed, otherwise As C = New C() would not be possible.

Public MustInherit Class GenericInterval(Of T As {Structure, IComparable})
    Public Value As T

    '(2) filled in below

    Private Function Add(Of U As {Structure, IComparable},
                            C As {IAddable(Of U), New}) _
                        (ByVal a As U, ByVal b As U) As U

        Dim calc As C = New C()
        Return calc.Add(a, b)
    End Function
End Class

Now I intended to use this function to do calculations in the class' overridden GetHashCode function, as follows:

Public MustInherit Class GenericInterval(Of T As {Structure, IComparable})
    Public Value As T

    Public Overrides Function GetHashCode() As Integer
        Const HASHPRIME_1 As Int64 = 4294967291    '32 bits.
        Dim lCompHash As Int64          'Partial hash for actual component.

        lCompHash = Add(Of T, Int64Calculator)(Value, HASHPRIME_1)
    End Function

    '... as above
End Class

However, VS complains with error BC32044, the squiggly underlines referring to

Add(Of T, Int64Calculator)

stating

"Type argument 'Int64Calculator' does not inherit from or implement the constraint type 'IAddable(Of T As {Structure, IComparable})'".

Only that I think that the structure Int64Calculator does implement that constraint indeed via Implements IAddable(Of Int64).

What do I miss?

  • 1
    `GenericInterval` does not enforce `T` to be `Int64`. So at the point when `Int64Calculator` is tested for validity, it is required to handle any `T as {Structure, IComparable}`, not just `Int64`. You can fix that with `lCompHash = Me.Add(Of Int64, Int64Calculator)(Me.Value, HASHPRIME_1)`, but then you'll have another error about `Me.Value` not necessarily being convertable to `Int64`. – GSerg Apr 17 '19 at 12:07
  • @GSerg I think this is the answer and that you should post it. – Grax32 Apr 18 '19 at 14:25
  • @Grax I didn't on the basis that it does not explain what to do with the `Me.Value` situation, so it just changes the problem to a different problem. – GSerg Apr 18 '19 at 14:26
  • @GSerg, I appreciate your explanation, but will still wait 1 or 2 more days for maybe a slightly different working approach, after which I would ask you to turn it into an answer proper, too, as "unsolvable" for sure is a valid answer. Of course, if I was just after the addability without caring for OO and strong typing, and was certain that only number types could be processed (possibly using narrower constraints, if I find any), one could simply do `Dim oValue as Object = Value` followed by `lCompHash = CType(oValue, Int64)` (with floats rounding). –  Apr 18 '19 at 15:13
  • @Herb Could you explain what you are [ultimately trying to do](https://meta.stackexchange.com/q/66377/147640) and how the intended use of `GenericInterval` would look like? – GSerg Apr 18 '19 at 15:24
  • @GSerg, I could write several pages about its use (I did already in Word, actually), but here, this is not the point. _I do not need arithmetics in this class. Absolutely not._ But I do need to implement `IComparable` and need also to override `Equals`. Which is done without any arithmetics. So far, so good. However, MS strongly advises to override also `GetHashCode` ((1) reference source, and worse (2) here) when doing so. It is _just here_ that I need maths. There will be more generics with the exact same problem. I thought an interface would be possibly a good idea. Maybe it wasn't. –  Apr 18 '19 at 15:57
  • (1) [link](https://referencesource.microsoft.com/#mscorlib/system/object.cs,4de9cf234d0d8b16), (2) [link](https://learn.microsoft.com/en-us/dotnet/api/system.object.gethashcode?view=netframework-4.7.2) –  Apr 18 '19 at 15:57
  • You're probably better off going with `public override int GetHashCode() { return Tuple.Create(x, y).GetHashCode(); } ` where `x` and `y` (and possibly other values) are the values that you use in your equality comparison. – Grax32 Apr 19 '19 at 13:15

1 Answers1

0

Part 1:
As @Gserg commented:
GenericInterval does not enforce T to be Int64. So at the point when Int64Calculator is tested for validity, it is required to handle any T as {Structure, IComparable}, not just Int64. You can fix that with lCompHash = Me.Add(Of Int64, Int64Calculator)(Me.Value, HASHPRIME_1), but then you'll have another error about Me.Value not necessarily being convertable to Int64.

Part 2:
This simplest way to implement GetHashCode for the case where you consider objects as equal based on certain properties is to use Tuple.Create(x,y).GetHashCode()

For example, if you consider properties equal that have the same Name and PhoneNumber properties, then the following code would return a usable HashCode.

public override int GetHashCode() { return Tuple.Create(Name, PhoneNumber).GetHashCode(); }
Grax32
  • 3,986
  • 1
  • 17
  • 32