Feature #6641

Hash.auto constructor

Added by Thomas Sawyer almost 2 years ago. Updated about 1 year ago.

[ruby-core:45822]
Status:Open
Priority:Normal
Assignee:Yukihiro Matsumoto
Category:core
Target version:next minor

Description

=begin
It is not uncommon to need a Hash following the pattern:

Hash.new{ |h,k| h[k]={} }

Another common example:

Hash.new{ |h,k| h[k]=[] }

This is common enough that it would very nice if we could have a more concise form, e.g.

Hash.auto{ {} }

Or for the second example:

Hash.auto{ [] }

Pure Ruby implementation is pretty simple:

def Hash.auto
Hash.new{ |h,k| h[k] = yield }
end

I think it would be nice to have in Core.

This is secondary, but it just occurred to me. Could there even be a literal notation for the above? Something like:

{}([])

?
=end

History

#1 Updated by Benoit Daloze almost 2 years ago

trans (Thomas Sawyer) wrote:

It is not uncommon to need a Hash following the pattern:

Hash.new{ |h,k| h[k]=[] }

This is common enough that it would very nice if we could have a more concise form, e.g.

Hash.auto{ [] }

I agree, this is a pattern I see quite often and the Hash.new { |h,k| h[k] = ... } form is not the most natural or expressive in my opinion.
But at the same time, this is clearly a specialization of Hash.new with a block, which loses some flexibility (you can not use the key for example). I'm curious what others think of it.

#2 Updated by Rodrigo Rosenfeld Rosas almost 2 years ago

Maybe something like Hash.withdefault{[]}. "withdefault" could be both a class and an instance method so that you could have something like {a: 1, b: 2}.with_default(0).merge... It would always return the hash itself...

Groovy has something like this (not quite the same behavior). In Groovy you can define default values as [:].withDefault{0}. You can optionally use the block argument as the key.

So I guess it would be great if Ruby with_default supported all those syntax below:

Hash.withdefault(0)
Hash.with
default{Time.now}
Hash.withdefault{|k| k.tosym}
{}.withdefault(0)
{}.with
default{Time.now}
{}.withdefault{|k| k.tosym}

#3 Updated by Jens Wille almost 2 years ago

Eregon (Benoit Daloze) [2012-06-25 12:33]:

But at the same time, this is clearly a specialization of
Hash.new with a block, which loses some flexibility (you can not
use the key for example).
why not? you can yield the key to the block.

I'm curious what others think of it.
i like it and i use it occasionally:

http://blackwinter.github.com/ruby-nuggets/Nuggets/Hash/NestMixin.html
https://github.com/blackwinter/ruby-nuggets/blob/master/lib/nuggets/hash/nest_mixin.rb
https://github.com/blackwinter/ruby-nuggets/blob/master/spec/nuggets/hash/nest_spec.rb

#4 Updated by Nobuyoshi Nakada almost 2 years ago

-1.
I don't like the destructive default proc, which sets new keys automatically.

#5 Updated by Motohiro KOSAKI almost 2 years ago

Hash.withdefault(0)
Hash.with
default{Time.now}
Hash.withdefault{|k| k.tosym}
{}.withdefault(0)
{}.with
default{Time.now}
{}.withdefault{|k| k.tosym}

I like with_default than auto. It describe the behavior more preciously.
auto is too vague to me.

#6 Updated by Yutaka HARA over 1 year ago

  • Target version changed from 2.0.0 to next minor

#7 Updated by Matthew Kerwin about 1 year ago

I agree with nobu-shi, if I were to encounter Hash::with_default &block I would assume it was the equivalent of:

Hash.new{ |h,k| yield }

rather than:

Hash.new{ |h,k| h[k] = yield }

Perhaps there could be ::withdefault and ::withdefault!

#8 Updated by Koichi Sasada about 1 year ago

  • Assignee set to Yukihiro Matsumoto

Also available in: Atom PDF