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
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
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.
Thank you. That worked great! I was not aware of
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.
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 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.
Thank you @jgaskins. That was helpful.