Crystal: Impossible to create Hash of String => Object

Created on 15 Jun 2017  路  10Comments  路  Source: crystal-lang/crystal

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

duplicate

Most helpful comment

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")}

All 10 comments

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

Was this page helpful?
0 / 5 - 0 ratings

Related issues

ArthurZ picture ArthurZ  路  3Comments

Sija picture Sija  路  3Comments

lgphp picture lgphp  路  3Comments

jhass picture jhass  路  3Comments

asterite picture asterite  路  3Comments