The Crystal Programming Language Forum

Can't access hash value based on type in macro

class Foo
end
 
class Bar
end
 
CONST = {
  Int32 => Foo,
  Int64 => Bar
}
 
 
{{pp CONST[Int32]}} # => nil

https://play.crystal-lang.org/#/r/7wz2

I also tried wrapping it in macro finished. Using String keys works fine, just not like Int32.class. Am I missing something?

I think in the CONST definition Int32 is just a Path node, but in the macro call it’s a TypeNode, and they are not equal. We could make try to make them equal, or resolve hash keys but it’s a bit complex… why do you need this?

For example this works:

class Foo
end

class Bar
end

CONST = {Int32 => 1}

macro path(path)
  {{puts CONST[path]}}
end

path(Int32)

The reason is that Int32 is passed as a Path node to the macro, and it remains a Path unless you resolve it. But in macros a Path is immediately resolved.

We could maybe add a path macro method to get a Path, for example doing {{ path(Int32) }} would get you Int32 as a Path node.

But macros are already pretty complex. As I always say, I would try to avoid them at all cost, except for simple uses.

Ah that makes sense. I was playing around with some refactoring in Granite where I would map a Crystal type to a record representing a database type. like {Int32 => Integer, Int64 => BigInteger} that internally would handle how to convert the value to/from the database. I could easily enough just use String keys, was just curious if there was something else going on.

Having a TypeNode#path would help in this case, do i open an issue? (or someone else, i don’t have much more right now)

TypeNode#path is not good because if you type Bar it might resolve to Foo::Bar and then the path will be Foo::Bar, not Bar. In fact, matching on Path might not be good because of this reason, so I don’t know.