[Facets] Multiple arguments for Hash#delete

This may be a Facet:

   class Hash
     alias_method :__delete__, :delete

     def delete(*keys, &block)
       if keys.length == 1
         __delete__(keys.first, &block)
       else
         keys.map{|key| __delete__(key, &block) }
       end
     end
   end

Probably somewhat slower, but hey, it lets you do this

   a, b, c = hsh.delete :a, :b, :c

which fits in nicely with

   hsh[:a, :b, :c] = 1, 2, 3

and

   a, b, c = hsh[:a, :b, :c]

Cheers,
Daniel

Daniel Schierbeck wrote:

This may be a Facet:

   class Hash
     alias_method :__delete__, :delete

     def delete(*keys, &block)
       if keys.length == 1
         __delete__(keys.first, &block)
       else
         keys.map{|key| __delete__(key, &block) }
       end
     end
   end

Probably somewhat slower, but hey, it lets you do this

   a, b, c = hsh.delete :a, :b, :c

which fits in nicely with

   hsh[:a, :b, :c] = 1, 2, 3

and

   a, b, c = hsh[:a, :b, :c]

Good deal. I'll add it. Looks to be a safe override too.

Perhaps this is a good update for future version of Ruby?

T.

Hi,

At Thu, 17 Aug 2006 04:05:08 +0900,
Daniel Schierbeck wrote in [ruby-talk:208833]:

Probably somewhat slower, but hey, it lets you do this

   a, b, c = hsh.delete :a, :b, :c

What will be returned from `hsh.delete :a'?

···

--
Nobu Nakada

Trans wrote:

Daniel Schierbeck wrote:

This may be a Facet:

   class Hash
     alias_method :__delete__, :delete

     def delete(*keys, &block)
       if keys.length == 1
         __delete__(keys.first, &block)
       else
         keys.map{|key| __delete__(key, &block) }
       end
     end
   end

Probably somewhat slower, but hey, it lets you do this

   a, b, c = hsh.delete :a, :b, :c

which fits in nicely with

   hsh[:a, :b, :c] = 1, 2, 3

and

   a, b, c = hsh[:a, :b, :c]

Good deal. I'll add it. Looks to be a safe override too.

For once... :slight_smile:

Perhaps this is a good update for future version of Ruby?

I think the updated #, #= and #delete all deserve to be in core. The only problem I see is performance-wise, although implementing them in C might help there.

Cheers,
Daniel

nobu@ruby-lang.org wrote:

Hi,

At Thu, 17 Aug 2006 04:05:08 +0900,
Daniel Schierbeck wrote in [ruby-talk:208833]:

Probably somewhat slower, but hey, it lets you do this

   a, b, c = hsh.delete :a, :b, :c

What will be returned from `hsh.delete :a'?

The value of :a

   hsh = {:a => 1, :b => 2, :c => 3}
   hsh.delete :a, :b #=> [1, 2]
   hsh.delete :c #=> 3

that way, you can do this

   a = hsh.delete :a
   b, c = hsh.delete :b, :c

Cool, right?

Cheers,
Daniel

Daniel Schierbeck wrote:

> Hi,
>
> At Thu, 17 Aug 2006 04:05:08 +0900,
> Daniel Schierbeck wrote in [ruby-talk:208833]:
>> Probably somewhat slower, but hey, it lets you do this
>>
>> a, b, c = hsh.delete :a, :b, :c
>
> What will be returned from `hsh.delete :a'?

The value of :a

   hsh = {:a => 1, :b => 2, :c => 3}
   hsh.delete :a, :b #=> [1, 2]
   hsh.delete :c #=> 3

that way, you can do this

   a = hsh.delete :a
   b, c = hsh.delete :b, :c

Cool, right?

Ah, Nobu has a good point. It's beeter to have same kind of output. He
also jogs my memory. Array has #delete_values_at and that's what we
need for Hash too.

def delete_values_at(*keys, &block)
    keys.map{|key| delete(key, &block) }
  end

Kind of long name though, maybe #delete_at would suffice?

T.

···

nobu@ruby-lang.org wrote:

Hi,

At Thu, 17 Aug 2006 23:40:18 +0900,
Daniel Schierbeck wrote in [ruby-talk:208980]:

>> Probably somewhat slower, but hey, it lets you do this
>>
>> a, b, c = hsh.delete :a, :b, :c
>
> What will be returned from `hsh.delete :a'?

The value of :a

   hsh = {:a => 1, :b => 2, :c => 3}
   hsh.delete :a, :b #=> [1, 2]
   hsh.delete :c #=> 3

The class of returned value varies according to the number of
arguments?

that way, you can do this

   a = hsh.delete :a
   b, c = hsh.delete :b, :c

     a = [:b, :c]
     b = hsh.delete(*a)

might be confusing, IMHO.

···

--
Nobu Nakada

nobu@ruby-lang.org wrote:

   hsh = {:a => 1, :b => 2, :c => 3}
   hsh.delete :a, :b #=> [1, 2]
   hsh.delete :c #=> 3

The class of returned value varies according to the number of
arguments?

Yes. I don't see that as a big problem though, especially if there's a second method that *always* returns an array:

   hsh.delete_at :a #=> [1]
   hsh.delete_at :b, :c #=> [2, 3]

It may be too much magic for some, but I think it's a very cool feature that won't interfere with how #delete is being used at the moment.

The main reason for it becoming a Facet is that Hash# and Hash#= also work with multiple arguments.

Cheers,
Daniel

Trans wrote:

Daniel Schierbeck wrote:

Hi,

At Thu, 17 Aug 2006 04:05:08 +0900,
Daniel Schierbeck wrote in [ruby-talk:208833]:

Probably somewhat slower, but hey, it lets you do this

   a, b, c = hsh.delete :a, :b, :c

What will be returned from `hsh.delete :a'?

The value of :a

   hsh = {:a => 1, :b => 2, :c => 3}
   hsh.delete :a, :b #=> [1, 2]
   hsh.delete :c #=> 3

that way, you can do this

   a = hsh.delete :a
   b, c = hsh.delete :b, :c

Cool, right?

Ah, Nobu has a good point. It's beeter to have same kind of output. He
also jogs my memory. Array has #delete_values_at and that's what we
need for Hash too.

def delete_values_at(*keys, &block)
    keys.map{|key| delete(key, &block) }
  end

Kind of long name though, maybe #delete_at would suffice?

Read my mind... yes, I think there should be added a #delete_at method in addition to the new #delete.

Cheers,
Daniel

···

nobu@ruby-lang.org wrote:

Daniel Schierbeck wrote:

Read my mind... yes, I think there should be added a #delete_at method
in addition to the new #delete.

Here' is another place in which the interchangeability between Array
andHash is lacking. Array has delete_at(index), while Hash has
delete(key). These two methods should really have the same name. But
array's delete() method is delete(value), which Hash has no equivalent.
Maybe matz will be willing to do a little shuffling to improve this for
2.0, but the only choice I have in the mean time is the long winded
delete_values_at().

Also, it really doesn't work to redefine delete() as you originally
suggested b/c you'd have to use the delete_values_at to ensure you get
an expected result, otherwise you're assuming preknowledge of how many
elemets are in the Hash.

T.

Then it probably shouldn't go into Ruby. Especially if you are proposing two deletion methods that I have to figure out in order to get the behavior I want.

My brain is full enough, thanks.

···

On Aug 17, 2006, at 9:05 AM, Daniel Schierbeck wrote:

nobu@ruby-lang.org wrote:

   hsh = {:a => 1, :b => 2, :c => 3}
   hsh.delete :a, :b #=> [1, 2]
   hsh.delete :c #=> 3

The class of returned value varies according to the number of
arguments?

Yes. I don't see that as a big problem though, especially if there's a second method that *always* returns an array:

  hsh.delete_at :a #=> [1]
  hsh.delete_at :b, :c #=> [2, 3]

It may be too much magic for some

--
Eric Hodel - drbrain@segment7.net - http://blog.segment7.net
This implementation is HODEL-HASH-9600 compliant

http://trackmap.robotcoop.com

Trans wrote:

Also, it really doesn't work to redefine delete() as you originally
suggested b/c you'd have to use the delete_values_at to ensure you get
an expected result, otherwise you're assuming preknowledge of how many
elemets are in the Hash.

What do you mean? It would work fine for the purpose I've described. If you want to be sure you get an array when deleting multiple key-value pairs, use #delete_values_at, otherwise #delete is just fine. The nifty thing is that it adjusts its return value according to your need.

If #delete should be altered, why should # and #= ?

Cheers,
Daniel

Eric Hodel wrote:

···

On Aug 17, 2006, at 9:05 AM, Daniel Schierbeck wrote:

nobu@ruby-lang.org wrote:

   hsh = {:a => 1, :b => 2, :c => 3}
   hsh.delete :a, :b #=> [1, 2]
   hsh.delete :c #=> 3

The class of returned value varies according to the number of
arguments?

Yes. I don't see that as a big problem though, especially if there's a second method that *always* returns an array:

  hsh.delete_at :a #=> [1]
  hsh.delete_at :b, :c #=> [2, 3]

It may be too much magic for some

Then it probably shouldn't go into Ruby. Especially if you are proposing two deletion methods that I have to figure out in order to get the behavior I want.

Well, I only seriously suggested to add it to Facets.

Cheers,
Daniel

Hi,

At Sat, 19 Aug 2006 03:56:56 +0900,
Eric Hodel wrote in [ruby-talk:209285]:

···

> nobu@ruby-lang.org wrote:
>>> hsh = {:a => 1, :b => 2, :c => 3}
>>> hsh.delete :a, :b #=> [1, 2]
>>> hsh.delete :c #=> 3
>> The class of returned value varies according to the number of
>> arguments?
>
> Yes. I don't see that as a big problem though, especially if
> there's a second method that *always* returns an array:
>
> hsh.delete_at :a #=> [1]
> hsh.delete_at :b, :c #=> [2, 3]
>
> It may be too much magic for some

Then it probably shouldn't go into Ruby. Especially if you are
proposing two deletion methods that I have to figure out in order to
get the behavior I want.

Possiblly, we have to wait until "true multi-value" is
introduced.

--
Nobu Nakada

Daniel Schierbeck wrote:

Trans wrote:
> Also, it really doesn't work to redefine delete() as you originally
> suggested b/c you'd have to use the delete_values_at to ensure you get
> an expected result, otherwise you're assuming preknowledge of how many
> elemets are in the Hash.

What do you mean? It would work fine for the purpose I've described. If
you want to be sure you get an array when deleting multiple key-value
pairs, use #delete_values_at, otherwise #delete is just fine. The nifty
thing is that it adjusts its return value according to your need.

Yea, I'm just saying YAGNI b/c in the end you won't use delete() with
more than one index, you'll use #delete_values_at b/c of the clear
separation of functionality. But...

If #delete should be altered, why should # and #= ?

You may have a point. Though it doesn't matter as much becuase it's
much less often the anyone depends on the return value of =. ie. we
just use it to set values. But to be very percise it should probably be
changed to match Array's. Consider that Array's = method does take
multuiple parameters related to slicing. Facets' deals with that by
allowing it to also take an Array parameter:

  a =
  a[[1,2,3]] = :a, :b, :c
  a #=> [ :a, :b, :c ]

Hash's can be made to do the same. What do you think?

T.

Trans wrote:

If #delete should be altered, why should # and #= ?

You may have a point. Though it doesn't matter as much becuase it's
much less often the anyone depends on the return value of =. ie. we
just use it to set values.

I only added #= because, with Facets, you can do this (as you of course know)

   hsh[:a, :b, :c] = 1, 2, 3

which matches nicely with

   a, b, c = hsh[:a, :b, :c]

My point is that #delete is also a retrieval method, in the sense that it returns the value it has removed from the hash. Therefore it is natural for it to have the same functionality as #, which in turn means that we have to alter #delete in Facets.

   a, b, c = hsh.delete(:a, :b, :c)

Simple and elegant.

But to be very percise it should probably be
changed to match Array's. Consider that Array's = method does take
multuiple parameters related to slicing. Facets' deals with that by
allowing it to also take an Array parameter:

  a =
  a[[1,2,3]] = :a, :b, :c
  a #=> [ :a, :b, :c ]

Hash's can be made to do the same. What do you think?

Actually, I don't like that solution very much. It doesn't seem very elegant.

Cheers,
Daniel

Daniel Schierbeck wrote:

Trans wrote:
>> If #delete should be altered, why should # and #= ?
>
> You may have a point. Though it doesn't matter as much becuase it's
> much less often the anyone depends on the return value of =. ie. we
> just use it to set values.

I only added #= because, with Facets, you can do this (as you of
course know)

   hsh[:a, :b, :c] = 1, 2, 3

which matches nicely with

   a, b, c = hsh[:a, :b, :c]

My point is that #delete is also a retrieval method, in the sense that
it returns the value it has removed from the hash. Therefore it is
natural for it to have the same functionality as #, which in turn
means that we have to alter #delete in Facets.

   a, b, c = hsh.delete(:a, :b, :c)

Simple and elegant.

Yea, I know what you mean. Believe me I went through the same viewpoint
when working on this for Array. Unfortunately the simplicity and
elegance start to crumble when:

  a = hsh.delete(*array)

Which leads to things like:

  a = [hsh.delete(*array)].flatten

or

  a = hsh.delete(*array)
  case a
  when Array
    ...
  else
    ...
  end

Which means you'll just opt to use #delete_at anyway.

> But to be very percise it should probably be
> changed to match Array's. Consider that Array's = method does take
> multuiple parameters related to slicing. Facets' deals with that by
> allowing it to also take an Array parameter:
>
> a =
> a[[1,2,3]] = :a, :b, :c
> a #=> [ :a, :b, :c ]
>
> Hash's can be made to do the same. What do you think?

Actually, I don't like that solution very much. It doesn't seem very
elegant.

Yes, but sometime simplicity and elegance have to give way to
practicality. I do hope Matz will take some time to address the
"duckability" between Array and Hash for 2.0, though. That would
certainly go a long way toward simplicity and elegance more than
anything.

T.

Trans wrote:

Daniel Schierbeck wrote:

Trans wrote:

If #delete should be altered, why should # and #= ?

You may have a point. Though it doesn't matter as much becuase it's
much less often the anyone depends on the return value of =. ie. we
just use it to set values.

I only added #= because, with Facets, you can do this (as you of
course know)

   hsh[:a, :b, :c] = 1, 2, 3

which matches nicely with

   a, b, c = hsh[:a, :b, :c]

My point is that #delete is also a retrieval method, in the sense that
it returns the value it has removed from the hash. Therefore it is
natural for it to have the same functionality as #, which in turn
means that we have to alter #delete in Facets.

   a, b, c = hsh.delete(:a, :b, :c)

Simple and elegant.

Yea, I know what you mean. Believe me I went through the same viewpoint
when working on this for Array. Unfortunately the simplicity and
elegance start to crumble when:

  a = hsh.delete(*array)

Which leads to things like:

  a = [hsh.delete(*array)].flatten

or

  a = hsh.delete(*array)
  case a
  when Array
    ...
  else
    ...
  end

Which means you'll just opt to use #delete_at anyway.

Of course you will. In this case, #delete_at fits perfectly well with the intended usage. I just don't see the problem with using #delete_at in such a case, and #delete in cases where you have a known number of keys.

I propose Facets have *both* an altered #delete *and* a #delete_at method.

Cheers,
Daniel