Sometimes it seems handy to have an object with some configuration data, accessible globally. Since Crystal doesn’t have global variables anymore, my attempt was to utilize the forward_missing_to macro like this:
struct Conf
property foo : String?
property bar : String?
# ...many more properties...
property zzz : String?
end
module Config
extend self
@@config = Conf.new
forward_missing_to @@config
end
Config.foo = "foo"
But it doesn’t work: undefined method 'foo=' for Config:Module
So, the only option I see at the moment, is to use a constant:
CONFIG = Conf.new
CONFIG.foo = "foo"
p CONFIG.foo #=> "foo"
But using a constant feels semantically wrong. Is there a more elegant way?
I understand the need to save a few characters, but I don’t think we should keep designing Crystal for this purpose. I now thing having[quote=“sudo-nice, post:3, topic:915, full:true”]
Thank you for the suggestion, but calling Config.config.foo seems a bit superfluous.
[/quote]
You could do Config.instance.foo instead. I understand it’s more typing than Config.foo but I don’t think that’s necessarily bad or an issue. We should stop designing the language around reducing the number of characters typed.
Also, you can manually define the forwarding methods if forward_missing_to doesn’t work.
It’s not about saving a few characters, but about redundancy. One can write:
Config.some_config_name
or
Config.instance.name
and the first one feels clearer (despite being longer).
What meaning does instance serve in Config.instance.name? None. We use it just because we have to.
Currently, I see using a constant as the only option here.
Guys, I think you are steeping over the fact that module Config is also a constant, just bit less direct one. Sematically there is no difference between module Config and Config = Conf.new or Config.instance or anything else starting with a capital letter.
If you want an honest variable, you should either make it explicitely visible from all the relevant parts of your program, probably carrying it around in your method signatures, or make it implicitely visible everywhere using global constant namespace, at which point module Config is probably worse than Config = Conf.new, because you are using class variables with no good reason.
Also please be careful with the struct here, you are mutating it which is dangerous in Crystal.
Btw, why is forward_missing_to in the language. Looks like some kind of hack lmaoo. Is that actual real syntax? Looks out of place and I had to second guess what I was reading after I read it.
It enables trivial implementations of proxy objects (like decorators, presenters, or similar patterns), which are useful for object-design patterns like DCI.
Come to think about it, “constant” is a bit of a misnomer. You may expect that it’s not gonna be reassigned or garbage collected, but there are no promises regading its mutability. The latter is usually managed by type system.