I know I can use class as Hash key, but is it a good practice? Is there any drawbacks in terms of performance or testing?
{
SomeClassA: 'hash value',
AnotherClass: 'hash value'
}
I know I can use class as Hash key, but is it a good practice? Is there any drawbacks in terms of performance or testing?
{
SomeClassA: 'hash value',
AnotherClass: 'hash value'
}
{
SomeClassA: 'hash value',
AnotherClass: 'hash value'
}
Is actually equivalent to:
{
:SomeClassA => 'hash value',
:AnotherClass => 'hash value'
}
The keys are symbols. In the "new" literal hash syntax keys are just treated as literals which are cast into symbols (provided they are valid syntax).
To use constants, ranges or any other type of object you can dream up as keys you need to use hashrockets:
{
SomeClassA => 'hash value',
AnotherClass => 'hash value'
}
Is it a good practice?
Its a technique that could be used in few limited cases. For example to replace a series of if
statements.
def foo(bar)
if bar.is_a? SomeClassA
'hash value'
end
if bar.is_a? AnotherClass
'another value'
end
end
def foo(bar)
{
SomeClassA => 'hash value',
AnotherClass => 'another value'
}[bar]
end
But I would rather use a case statement there anyways as its clearer in intent and more flexible.
Are there any drawbacks in terms of performance or testing?
Each hash you create would have keys that point to the exact same objects in memory just like if you where using symbols.
One big gotcha is that Rails monkey-patches const_missing
to autoload files - when you reference a class name rails will load the file from the file system into memory. This is why you declare associations with:
class Foo < ApplicationRecord
belongs_to :bar, class_name: "Baz"
end
It lets Rails instead lazy load Baz when needed. You would do the same with the example above by:
def foo(bar)
{
'SomeClassA' => 'hash value',
'AnotherClass' => 'another value'
}[bar.name]
end
That hash is using symbols, not classes, as keys, but you can use a Class by doing
hash = { SomeClassA => "some value" }
I can't think of why it would be worse than using any other object because
Classes in Ruby are first-class objects---each is an instance of class
Class
So
{ SomeClassA => "some value" }
is functionally equivalent to
{ "Some String" => "some value" }
What you have there are not class keys but symbols. Try
class A
end
class B
end
hash = {A: "Some", B: "Code"}
hash.keys[0].class
=> Symbol
But still A.class
=> Class
In case of symbol performance this POST is great
Also you can check ruby documentation about user-defined class as hash keys
While you can do it, I can't think of a reason for using it. Using a symbol or string as the key is much more efficient as the program does not have to load the whole class. (a side note, as pointed by others, your example in fact is using a symbol key, and you'll need to use a hash rocket to use a class name as the key)