2014-04-25 8 views
10

Zauważyłem, co uważam za bardzo zaskakujące zachowanie z operatorem ** (double-splat) w Ruby 2.1.1.Operator z podwójnym splatem destruktywnie modyfikuje hash - czy jest to błąd Ruby?

Gdy pary klucz-wartość są używane przed **hash, skrót jest niezmieniony; jednak gdy pary klucz-wartość są używane tylko po **hash, skrót jest trwale zmodyfikowany.

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 } 

Dla porównania, za zachowanie jedno- * operatora na tablicach:

a = [2] 

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

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

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

Tablica pozostaje bez zmian w całym tekście.


Czy sądzimy niekiedy destrukcyjne zachowanie ** jest zamierzone, czy to wygląda bardziej jak robaka?

W obu przypadkach, gdzie jest dokumentacja opisująca działanie operatora **?


Też zapytałem to pytanie in the Ruby Forum.

UPDATE

Błąd jest stała w Ruby 2.1.3+.

+2

Użycie na listach parametrów znajduje się w głównej dokumentacji http://www.ruby-doc.org/core-2.1.1/doc/syntax/methods_rdoc.html. Hash i tablica interpolacja nie wydają się pojawiać nigdzie tam, chociaż single spat przynajmniej ma spec: https://github.com/rubyspec/rubyspec/blob/master/language/splat_spec.rb. Nie ma nic podobnego do podwójnej kłótni. Semantyka ruby ​​wydaje się folklorystyczna. Jestem pewien, że to jest błąd, ponieważ nieudokumentowana funkcja językowa może być błędna! – Gene

+0

Nie wiedziałem nawet, że możesz używać tego w podpisie metody none ... – phoet

+2

Wygląda na to, że skompilowany skrót jest tym samym obiektem, co pierwszy element w nim, jeśli jest hash (mają one ten sam identyfikator obiektu). Właśnie dlatego są one modyfikowane. Kiedy masz dwa hashe 'h' i' i' oraz '' '**, **, d: 5}', modyfikowane jest tylko 'h', a nie' i'. – sawa

Odpowiedz

7

Odpowiedzi na pytania wydają się być:

  1. To chyba błąd, raczej niż zamierzone.

  2. Zachowanie operatora ** zostało bardzo krótko udokumentowane w dokumencie core library rdoc.

Dzięki sugestiom kilku komentujących, wysłałem błąd do Ruby trunk issue tracker.


UPDATE:

Błąd został naprawiony w changeset r45724. Komentarz był "słowo kluczowe nie powinno być niszczące", co czyni to autorytatywna odpowiedź.

+0

Błąd już wydaje się być [naprawiony] (https://bugs.ruby-lang.org/projects/ruby-trunk/repository/revisions/45724). To było szybkie. – sawa

+0

@sawa Jest szybki, ale trzeba powiedzieć, że wygląda jak włamanie, a potem poprawka. Wystarczy nadpisanie wskaźników z poprzedniego połączenia płytką kopią skrótu, z pominięciem pełnego warunku. Czuję się trochę zawstydzony. –

+0

@sawa Dzięki, też to widziałem. Myślę, że zgadzam się z Davidem, jednak poprawka wyglądała bardzo podobnie do hackowania. –

1

I zauważył Diff pomiędzy 2.1.5 i 2.3.1

przykładzie jest IRB sposób i sposób wywoływania jej

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

W 2.1.5 następujące wyniki w utrzymaniu wartości

=> {:a=>"a"} 

W 2.3.1 wartość to "b"

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

Nie jestem pewien, który powinien być?

W 2.3.1 skrót wprowadzony jako podwójna ikona przesłonił ten sam klucz pierwszego elementu na liście.