Search code examples
crystal-lang

Is it possible to extend class for limited types only?


I would like to add normalize method to Arrays of Numbers only (Float & Int) as it doesn't make sense for String. But it won't compile, is that possible?

class Array(Number)
  def normalize
    multiplier = 1 / max
    map{ |v| multiplier * v }
  end
end

p [1, 2].normalize

Solution

  • This is not possible, as I'm sure you've seen. As such, you have two options.

    1) You can extend the class into a new one that just uses the type you want.

    class NumberArray < Array(Number)
      # Do something
    end
    

    The obvious downside being that you can't use an Array(Number) as a NumberArray.

    2) You can write a guard clause around the normalize method that checks the array type and makes sure it's a number array.

    class Array(T)
      def normalize
        {% unless T < Number %}
          {% raise "Expected Number type for Array#normalize, got #{T}" %}
        {% end %}
        multiplier = 1 / max
        map { |v| multiplier * v }
      end
    end