2014-04-25 12 views
10

Ho notato che trovo un comportamento molto sorprendente con l'operatore ** (double-splat) in Ruby 2.1.1.L'operatore double-splat modifica in modo distruttivo l'hash: si tratta di un bug di Ruby?

Quando le coppie valore-chiave sono utilizzate prima di un **hash, l'hash rimane non modificato; tuttavia, quando le coppie valore-chiave vengono utilizzate solo dopo lo **hash, l'hash viene modificato in modo permanente.

h = { b: 2 } 

{ a: 1, **h }  # => { a: 1, b: 2 } 
h     # => { b: 2 } 

{ a: 1, **h, c: 3 } # => { a: 1, b: 2, c: 3 } 
h     # => { b: 2 } 

{ **h, c: 3 }  # => { b: 2, c: 3 } 
h     # => { b: 2, c: 3 } 

Per confronto, si consideri il comportamento del * operatore singolo su array:

a = [2] 

[1, *a]  # => [1, 2] 
a   # => [2] 

[1, *a, 3] # => [1, 2, 3] 
a   # => [2] 

[*a, 3]  # => [2, 3] 
a   # => [2] 

L'array rimane invariato per tutta.


facciamo noi supponiamo il comportamento a volte distruttiva di ** è intenzionale, o lo fa sembrare più come un insetto?

In entrambi i casi, dov'è la documentazione che descrive come deve funzionare l'operatore **?


Ho anche posto questa domanda in the Ruby Forum.

UPDATE

Il bug è stato risolto in Ruby 2.1.3+.

+2

L'utilizzo negli elenchi di parametri si trova nella documentazione di base http://www.ruby-doc.org/core-2.1.1/doc/syntax/methods_rdoc.html. Hash e l'interpolazione letterale dell'array non sembrano apparire da nessuna parte, anche se il singolo sputo ha almeno una specifica: https://github.com/rubyspec/rubyspec/blob/master/language/splat_spec.rb. Non c'è niente di simile per il doppio splat. Semantica rubino sembra essere folcloristico. Sono sicuro che si tratta di un errore nella misura in cui una funzione di linguaggio non documentato può essere bacata! – Gene

+0

non sapevo nemmeno che ti fosse permesso usarlo in una firma di nessun metodo ... – phoet

+2

Sembra che l'hash composto sia lo stesso oggetto del primo elemento in esso se è un hash (hanno lo stesso ID oggetto). Questo è il motivo per cui sono stati modificati. Quando hai due hash 'h' e' i' e fai '{** h, ** i, d: 5}', solo 'h' viene modificato, non' i'. – sawa

risposta

7

Le risposte alla domanda sembrano essere:

  1. E 'probabilmente un bug, piuttosto che intenzionale.

  2. Il comportamento dell'operatore ** è documentato molto brevemente nello core library rdoc.

Grazie ai suggerimenti di diversi commentatori, ho postato il bug su Ruby trunk issue tracker.


UPDATE:

Il bug è stato fissato in changeset r45724. Il commento è stato "keyword splat dovrebbe essere non distruttivo", che rende questa una risposta autorevole.

+0

Il bug sembra già essere stato [riparato] (https://bugs.ruby-lang.org/projects/ruby-trunk/repository/revisions/45724). È stato veloce. – sawa

+0

@sawa È veloce, ma devo dire che sembra un hack e una correzione. Basta sovrascrivere i puntatori della precedente chiamata con una copia superficiale di Hash, omettendo la condizione completa. Mi sento un po 'imbarazzato. –

+0

@sawa Grazie, l'ho visto anche io. Penso di essere d'accordo con David, tuttavia, la correzione sembrava molto simile a un trucco. –

1

ho notato il diff tra 2.1.5 e 2.3.1

esempio è un metodo IRB e un modo di chiamarla

$ irb 
>> def foo(opts) opts end 
=> :foo 
>> foo a: 'a', ** {a: 'b'} 

Nella 2.1.5 i seguenti risultati a trattenere valore

=> {:a=>"a"} 

In 2.3.1 il valore è 'b'

(irb):2: warning: duplicated key at line 2 ignored: :a 
=> {:a=>"b"} 

Non sono sicuro quale dovrebbe essere?

In 2.3.1 l'hash fornito come double splat sovrascrive la stessa chiave del primo elemento in una lista.