habitat
habitat copied to clipboard
Problem in macro create_settings_methods when global Nil class shadow by local with same name
I came across a case where the name of the class Nil is contained in the module in which the class for which we create the settings is defined.
module A
class Nil
end
class B
Habiat.create do
setting abc : Array(Something) = Array(Something)
end
end
end
In this case, the macro does not work correctly because it refers to a local A::Nil and not a global Nil class.
> 19 | # then raise a MissingSettingError
> 20 | @@abc : Array(Something.class) | Nil = begin
> 21 | Array(Something.class).new
^
Error: class variable '@@abc' of A::B::HabitatSettings must be (Array(Something.class) | A::Nil), not (Array(Something.class) | Nil)
Without spoiling the idea of how smart it is to have a separate class Nil inside a local namespace, this can be fixed in code
setting abc : Array(Something) | Nil | ::Nil = Array(Something)
but I propose to explicitly specify the global ::Nil in this macro body if this possible.
https://github.com/luckyframework/habitat/blob/4d242eb524e00289fb5857ed1bd786ec96670a5d/src/habitat.cr#L239-L293
That seems like a reasonable fix; however, I would suggest to not create a class called Nil. Crystal Nil is a struct https://github.com/crystal-lang/crystal/blob/739461fe78c6ce65033f009af3e360750d5b020d/src/nil.cr#L44 and I think having a type with the same name that's treated differently could lead to other issues within the code.
One thing we do in Avram to use an object that means "nothing" but isn't Nil is using a class called Nothing
https://github.com/luckyframework/avram/blob/main/src/avram/nothing.cr
Thanks for the tip with Nothing, great solution, wonder if i can use it as it is a very big legacy shard(