Is there any way to explicitly allow Arithmetic overflow, for hash calculations?

Hello,

I’m trying to fix a bug in the mocks.cr shard. (Here’s my issue on GitHub.) It’s doing some hash calculations like this:

      def hash
        object_id.hash * 32 + args.hash
      end

      # ...

      def hash
        @registry_name.hash * 32 * 32 + @name.hash * 32 + @object_id.hash
      end

These are crashing with OverflowError: Arithmetic overflow:

     Error: Arithmetic overflow

       OverflowError: Arithmetic overflow
         lib/mocks/src/mocks/registry.cr:86:60 in 'hash'
         /usr/local/Cellar/crystal/0.31.1/src/hash.cr:893:12 in 'key_hash'
         /usr/local/Cellar/crystal/0.31.1/src/hash.cr:336:5 in 'upsert'
         /usr/local/Cellar/crystal/0.31.1/src/hash.cr:912:5 in '[]='
         lib/mocks/src/mocks/registry.cr:104:9 in 'add'
         lib/mocks/src/mocks/registry.cr:156:9 in 'store_stub'
  ...

Is there any way I can tell the compiler that I don’t care about overflows, since this is a hashing algorithm where the final result just needs to be unique?

In the meantime, I’ve been able to fix these hash methods with some bit shifts (and sent a PR), to make sure it never overflows a UInt64:

      def hash
        (object_id.hash >> 2) + (args.hash >> 2)
      end

     # ...

      def hash
        (@registry_name.hash >> 3) + (@name.hash >> 3) + (@object_id.hash >> 3)
      end

Is there a better way to fix this issue?

1 Like

Arithmetic operators that can cause overflow can be prefixed by & to make them wrap.

2 Likes

Oh awesome, thank you!

(I couldn’t find this in the docs, but I just found it in the release notes for 0.27.0, under the ARITHMETIC CHANGES section.)

Yes, the operators reference is currently being worked on.

1 Like