Macros and forall

Hi,

I’m trying to create a macro that takes generic types as arguments but I keep getting Error: undefined constant.

Example code:

macro my_macro(t1, t2)
  # code ...
end

class Foo(T)
  def bar(x : U) forall U
    # code ...
    bar_var = my_macro(T, U) # <-- Error: undefined constant U
    # more code ...
  end
end

I have no idea why I get this error because, if I understand this this correctly, it should be possible?

It is possible but the code you provided doesn’t reproduce the error you mentioned.
Filling in the macro with some arbitrary code:

macro my_macro(t1, t2)
  {{t1}}.to_s + {{t2}}.to_s
end

class Foo(T)
  def bar(x : U) forall U
    # code ...
    bar_var = my_macro(T, U)
    # more code ...
  end
end

Foo(Int32).new.bar("") # => "Int32String"
1 Like

That’s weird.

Here is my actual code - maybe I missed something?

macro generate_vector(t1, t2)
  {% if !(t1.resolve < Float) && t2.resolve < Float %}
    # code ...
  {% else %}
    # code ...
  {% end %}
end

class Vector(T)
  def +(other : Vector(U)) forall U
    if self.size != other.size
      raise ArgumentError.new("vectors must be same size")
    end

    vec = generate_vector(T, U)
    # Error: undefined constant U :/
    self.each_with_index do |elem, i|
      vec << elem + other[i]
    end
    return vec
  end
end

Hi and welcome!

If you copy all of the code you are sharing so far into a text editor, and run crystal ... on it, it compiles fine.

Can you share some code that reproduces the error you are seeing?

Try replacing generate_vector(T, U) with generate_vector({{T}}, {{U}})

created a branch and pushed it to github.

repo

The code can be found in src/linalg/vector.cr and src/linalg/helpers/generators.cr

What I’m trying to is to replace the two generator methods (generate_vector and generate_matrix) with the macro code at the top in generators.cr

I’m not sure if this is an important information but I get the error when I run crystal spec

That gave me a new error but I got right back to undefined constant U when the error was fixed.

Change the following:

in generators.cr:

macro generate_vector(t1, t2)
  {% if !(t1.resolve < Float) && t2.resolve < Float %}
    Linalg::Vector({{t2.resolve}}).new
  {% else %}
    Linalg::Vector({{t1.resolve}}).new
  {% end %}
end

in vector.cr:

generate_vector(T, U) to generate_vector({{T}}, {{U}})

It worked for me.

2 Likes

You are my hero! I have been stucked on this almost all day.

Thank you!