facelessuser / coloraide

A library to aid in using colors
https://facelessuser.github.io/coloraide
MIT License
194 stars 12 forks source link

Should Color be hashable? #422

Closed NicholasFiorentini closed 3 months ago

NicholasFiorentini commented 3 months ago

I wanted to use Color in a frozen dataclass but, unfortunately, it is not hashable and it cannot be used directly.

Minimal example

from dataclasses import dataclass
from coloraide import Color

@dataclass(frozen=True)
class Colors:
    color_primary: Color
    color_background: Color

my_colors = Colors(
    color_primary=Color("red")
    color_background=Color("green")
)

Proposed solution

I implemented this very naive solution:

from coloraide import Color as ColoraideColor

class Color(ColoraideColor):
    def _hash_parts(self) -> tuple[float, ...]:
        # See ColoraideColor.__eq__: we take the space and color coordinates and convert to a tuple.
        # This ensures a reproducible hash.
        space = (float(ord(c)) for c in self.space())
        return tuple(space) + tuple(self[:])

    def __hash__(self) -> int:
        return hash(self._hash_parts())

Could this be part of coloraide's Color? Or there is a reason why Color is not hashable?

facelessuser commented 3 months ago

They are not immutable, so hashing doesn't make sense. You can change them at any time invalidating any hash I could generate.

You can manually save the color data as a hashable object, or serialize them as a hashable string, but the color object itself is mutable. This is the same reason dictionaries and lists aren't hashable.

facelessuser commented 3 months ago

If hashing is an absolute requirement for your specific usage, I think subclassing the object and hashing it yourself is perfectly fine. The caveat is that if you accidentally modify a color it would change its hash and potentially create a collision in your structure, but if you are comfortable with that risk and think the likeliness of such accidents is low, then it's a fine solution.

NicholasFiorentini commented 3 months ago

They are not immutable, so hashing doesn't make sense. You can change them at any time invalidating any hash I could generate.

Ah, I see. At first, I missed that Color is a mutable object.

Thanks for clarifying.