matz / zetabits.com (Yukihiro Matsumoto) wrote:
> Hi,
> 
> In message "[ruby-talk:5947] Hash.new {block} / Hash#default_proc{,_set}"
>     on 00/10/31, "Brian F. Feldman" <green / FreeBSD.org> writes:
> 
> |I've done very little testing, but I think I've successfully implemented the 
> |ability for a Hash to provide a default procedure rather than variable.
> |
> |The only reasonable way I could think of doing this required on-the-fly 
> |creation of a hash entry when a lookup fails -- otherwise, this feature is 
> |nearly useless (does not make anything easier).
> |
> |Here's the diff, my 3rd time modifying Ruby code itself.  Comments?
> 
> Three points:
> 
>   * currently each internal structure sizes are made strictly less
>     than 5 pointer size for space efficiency.

Hm, I see, with RVALUE.  I learned something new now!  Fixed...

>   * your on-the-fly entry creation idea sound reasonable; but I think
>     we need to discuss it before merging it.

Well, I've changed my little API a bit... default_proc is a flag to set and 
the behavior is deterministic based upon this.

>   * we need to inspect cost/benefit between this patch and Hash#fetch
>     which already takes a block to give a value for non existing
>     entry.

Perhaps.  It's just the idiomatic differences, really; you can currently do
(bear with the fact that this is an example that isn't too useful :)

hash[var] ||= 0; hash[var] += 1
hash[var] = hash.fetch(var, 0) + 1

Neither of these is optimal because they are too complicated to be a good 
idiom.

Maybe a "hash.fetch(var, 0) += 1"?  That would be impossible...  So onto 
"hash[var] += 1" -- this works for immutable types or non-modifying calls, 
but suppose I want to do:

lines = File.open(x) {|y| y.collect {|n| n.chomp!}}
if i_do_not_like_this_one
    def words_lines(lines)
	h = Hash.new
	lines.each_with_index {|l, i|
	    l.split.each {|w|
		h[w] ||= []
		h[w].push(l)
	    }
	}
    end
else
    def words_lines(lines)
	h = Hash.new {[]}
        # can't do this because Array.new is called only once:
	# h = Hash.new([])
	lines.each_with_index {|l, i|
	    l.split.each {|w|
		h[w].push(l)
	    }
	}
    end
end
puts words_lines(lines)

Which seems "nicer" to you?  I Like the second a lot more because it's 
idiomatic in the way 

This was an example of the issue brought up earlier (with << instead of push,
but...) on the list, but I don't recall which message number it was.

> Thank you anyway.

Just a proposal, thanks for looking :)

--
 Brian Fundakowski Feldman           \  FreeBSD: The Power to Serve!  /
 green / FreeBSD.org                    `------------------------------'