Use generic to define method

Is it possible to define methods relative to a generic type? Or access the generic type outside of methods at all? This:

module Moo(T)
  {% if T < Number %}
    def method(param1=true)
    end
  {% else  %}
    def method(param1=false)
    end
  {% end %}
end

yields this:


 3 | {% if T < Number %}
           ^
Error: undefined constant T

But if I put that same statement within the method, it compiles fine.

Any ideas on how to vary a parameter value based on a generic type? For now I’m going to just use an Enum and have it default to 'default" and override it within the method if it’s “default” :expressionless:

It doesn’t work like that because macros at the “top level” are expanded as soon as you reach them.

What you want is possible:

module Moo(T)
  def method
    method({{ T < Number }})
  end

  def method(param1)
  end
end
1 Like

Nice! So I can set a default based on type.

I’m trying to satisfy https://github.com/crystal-lang/crystal/issues/6057 and was hoping to set

def sort(stable = false) : Array(T)

with the “stable” set to false for Number types and true for Objects (since stable doesn’t matter for Numbers). It appears that I won’t be able to do that in the type signature…

Anybody have any ideas on how to accomplish this? Suggestions? Enum? Thanks for any help.

Update: It appears I can use something like a param whose default value is a method call to accomplish it, thanks for the hints:

class Moo(T)
  def get_type()
    {{ T < Number }}
  end

  def method(param1 = get_type())
   puts param1
  end
end

Moo(Int32).new.method # => true
Moo(String).new.method # => false

You could also avoid the method and drop the macro into the argument list:

class Moo(T)
  def method(param1 = {{ T < Number }})
   puts param1
  end
end

puts Moo(Int32).new.method # => true
puts Moo(String).new.method # => false
6 Likes

TIL

3 Likes