Fable icon indicating copy to clipboard operation
Fable copied to clipboard

[Python] Custom hash functions are never called on Record Types.

Open HLWeil opened this issue 11 months ago • 0 comments

Description

Custom hash functions are never called on Record Types.

Repro code

test.fsx

[<CustomEquality>]
[<NoComparison>]
type MyRecord = 

    {Name : string; Age: int }

    override this.Equals(that) =
        this.GetHashCode() = that.GetHashCode()

    /// Hash should just return age of person
    override this.GetHashCode() =
        this.Age

let p1 = {Name = "John"; Age = 30}

// Should return 30, but returns -4426817161268664163
printfn "Hash1: %A" (p1.GetHashCode())

test.cmd

dotnet fable . --lang python
python test.py

Explanation

In the transpiled code, the class MyRecord now implements a __hash__ method. But the method call is transpiled to safe_hash, which first checks for the existence of an GetHashCode method. This is always true for Record Types, so the custom __hash__ methdo is never called.

Related information

  • dotnet fable --version: 4.13.0
  • dotnet tool list/update/install: 4.13.0
  • Windows11

Workaround Code

#if FABLE_COMPILER_PYTHON
[<Emit("hasattr($0,\"__hash__\")")>]
let pyHasCustomHash (obj) : bool = nativeOnly
    
[<Emit("$0.__hash__()")>]
let pyCustomHash (obj) : int = nativeOnly
#endif

let hash obj =
    #if FABLE_COMPILER_PYTHON
        if pyHasCustomHash obj then
            pyCustomHash obj
        else
            obj.GetHashCode()
    #else
        obj.GetHashCode()
    #endif

@freymaurer

HLWeil avatar Mar 08 '24 08:03 HLWeil