I tried to create a bean registry to experiment with dependency injection, but I found myself unable to instantiate a Hash of String to Object.
I tried the following:
@registry = {} of String => Object
@registry = Hash(String, Object).new
Both gave me an error that I cannot use Object as type for a Hash YET, and to use a specific type.
Will this be fixed in a future release? Any workaround that someone found?
Thanks in advance
Use any more concrete type. Like JSON::Any (or compose your's one).
The problem is that I need to store arbitrary objects in a registry. That means I can't know in advance what type of object a user would use. JSON::Any works only for JSONs
/madskillz mode:
module Registrable
end
class Object
include Registrable
end
registry2 = {} of String => Registrable
registry2["array"] = [1,2,3]
registry2["string"] = "test"
pp registry2
not sure if this would cause problems later, i think it's better to store something more specific then Object
@MatteoJoliveau You will have to know the type of the object when retrieving it from the array so you should be able to use Box
to convert it to a Void*
and back. You'll need some checking on retrieval to make sure it's the same type though or bad things will happen.
The fact that https://github.com/crystal-lang/crystal/issues/4572#issuecomment-308768217 works really shows that there's no technical limitation to having Object
work generically.
@oprypin I imagine that it's very inefficient. sizeof(Registrable)
is going to be massive in a lot of programs so it's advisable to make it hard to do so that people new to the language don't do it and wonder why their arrays are truly massive. I see no reason now to allow Reference
though.
Sorry everybody, it doesn't works. I thought that is just carc.in
lags, but no - it makes compiler to fail (behavior different from version to version, in 0.22 runtime error raised in compiler), but general problem is that type information is lost, only registry2["string"].as(String)
works, not registry2["string"]
.
I tried this:
abstract class Any
end
class A(T) < Any
property this
def initialize(@this : T)
end
end
hash = {} of Any => Any
a = A.new("a")
b = A.new("b")
c = A.new("c")
hash[a] = A.new("value")
hash[b] = A.new(42)
hash[c] = A.new([3, 5, 7])
pp hash[a].this
hash[a] = A.new(1.0)
pp hash[a].this
pp hash
$ crystal any.cr
hash[a].this # => "value"
hash[a].this # => 1.0
hash # => {
#<A(String):0xb78f00 @this="a"> => #<A(Float64):0xb86fc0 @this=1.0>,
#<A(String):0xb78ee0 @this="b"> => #<A(Int32):0xb77fe0 @this=42>,
#<A(String):0xb78ec0 @this="c"> => #<A(Array(Int32)):0xb78e60 @this=[3, 5, 7]> }
Using record since this
shouldn't change:
abstract struct Any; end
record A(T) < Any, this : T
hash = {} of Any => Any
a = A.new("a")
b = A.new('b')
hash[a] = A.new([3, 5, 7])
hash[b] = A.new("value")
pp hash
hash[a] = A.new(1.0)
pp hash
$ crystal any.cr
hash # => {A(String)(@this="a") => A(Array(Int32))(@this=[3, 5, 7]),
A(Char)(@this='b') => A(String)(@this="value")}
hash # => {A(String)(@this="a") => A(Float64)(@this=1.0),
A(Char)(@this='b') => A(String)(@this="value")}
Duplicate of #2733
Most helpful comment
Using record since
this
shouldn't change: