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
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.
It took me a long time to wrap my head around this, as well, coming from Ruby where that would be perfectly acceptable.
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.