Accessing constants in a module. Unexpected behavior

Hi,
I am seeing some unexpected (to me) behavior when trying to access a constant from another module. Wondering if this is normal/expected or if it is a bug?

When I use the assigned name to a module to access its constant, the code fails to compile, but if I use the name of the module itself, the code compiles fine. I don’t have this problem when accessing methods from a module.

I am using Crystal 0.30.0

module AwesomeRoutes
    Uf = UtilFuncs ## another module (assigning a short name to it)
    get "/coolfeatures/crystallang" do |env|
         dirname = Uf::FIGS_DIR ## fails to compile
         dirname = UtilFuncs::FIGS_DIR ## compiles without error
         someaction = Uf::takeaction(a,b,c) ## no compilation error for methods
    end
end
1 Like

Try with alias Uf = UtilFuncs

As for why, this is because with Uf as a constant, it’s value UtilFuncs is a runtime knowledge, and the compiler can’t resolve X::Y at compile time, when X is a runtime thing…

Using alias makes Uf a type (known at compile time), which is an alias for another type for the compiler.

1 Like

Thank you. That worked great! I was not aware of alias.
I need to understand these things a little better. Why does it work for methods?

It took me a long time to wrap my head around this, as well, coming from Ruby where that would be perfectly acceptable. :smile:

Uf = UtilFuncs is treated similarly to uf = UtilFuncs, assigning a reference to the module.

alias Uf = UtilFuncs, rather than assigning a reference, tells the compiler to treat Uf as a type. Crystal makes a distinction between a type and a reference.

In Ruby you would be able to do uf::Foo if uf references a class/module. In Crystal, types can act as namespaces but references cannot. That might be limiting in some way but honestly I’ve only seen one instance where I’ve wanted to be able to do this and I worked around it pretty easily with a macro. :slightly_smiling_face:

3 Likes

Thank you @jgaskins. That was helpful.