How to get type of var in macro

code:

macro foo(obj)
  p {{ obj.type }}
end

record Book, name : String, price : Float32

book = Book.new("foo", 33)
foo book

output:

10 | foo book
          ^---
Error: undefined macro method 'Var#type'

The macro only knows it was given a variable, there isn’t a way to figure out the type of it at compile time given book is a runtime thing. Going to have to provide it manually as a second argument, or try and figure something else out.

Crystal isn’t the static type? The type of var should be inferenced in compile-time

You can use a normal def with a free variable:

def foo(obj : T) forall T
  {% p T %} # okay
  p T       # okay
end

Value type will cause copy , so macro must be used in some scenarios

Does it matter? Book is so small in this scenario that it shouldn’t.

Do you even need compile-time access to the variable’s type? Does book.class or typeof(book) not work for your use case?

for example:

def get_instance_pointer(t : T) : Pointer(T) forall T
  {% begin %}
    {% if T.struct? %}
      pointerof(t)
    {% elsif T.class? %}
      t.as(Pointer(T))
    {% else %}
      raise "{{T}} is neither struct nor class"
    {% end %}
  {% end %}
end

Do you realize that pointerof(t) is only valid within the method to which t is an argument?
If you leak that pointer outside the method, it will be broken because t on the stack is out of scope.

yes, so my question is How to get type of var in macro :upside_down_face:

You still don’t need to get the type in this case, because only runtime checks are needed, not compile-time checks:

macro get_instance_pointer(t)
  {% raise "`t` must be a Var, not #{t.class_name}" unless t.is_a?(Var) %}
  {{ t }}.is_a?(Reference) ? {{ t }}.as(Pointer(T)) : pointerof({{ t }})
end

But note that t.as(Pointer(T)) is simply invalid as that effectively introduces an additional level of indirection. I am not sure what get_instance_pointer is supposed to achieve.

1 Like

I just want to give an example to explain that if you can get variable types in the macro, you can do more ;-)

Thank you for your patience anyway