Macro & Inheritance

I though that in the inherited macro @type would be the inheriting type (aka the subclass), so I believed that I can write macros that expect a particulart constant (or variable) to be declared in a subclass.
But this example proves me wrong.

EDIT:
executing this code

module Foo
	class Bar  
      macro inherited
        {{ p! @type.has_constant?("C1")}}
        {{ p! @type.class_vars}}
        {{ p! @type}}
 
        def value
          @value.value
        end
 
 
        def initialize(@value : Int32)
        end
 
        def |(other : {{@type}})
          {{@type}}.new(@value | other.value)
        end
 
        def &(other : {{@type}})
          {{@type}}.new(@value & other.value)
        end
 
      end
  	end
  end
 
class MyBar < Foo::Bar
  C1 = "SomeString"
  {{ p! @type.has_constant?("C1") }}
end
 
puts

The output is:

@type.has_constant?("C1") # => false
@type.class_vars # => []
@type # => MyBar
@type.has_constant?("C1") # => true

Can someone explain this to me?

I would expect the first @type.has_constant?("C1") to be also true

If I had to guess I’d think that when the macro inherited code runs C1 hasn’t been created yet. Wrapping the code in a macro finished works.

https://play.crystal-lang.org/#/r/97b1

@asterite could probably speak more on if this is what’s going on.

macro inherited runs in this line

A workaround is to defer the macro code to a method:

macro inherited
  def self._inherited
    {% verbatim do %}
      # {{@type}} is populated here
    {% end %}
  end
  _inherited
end
1 Like