Zmiana wartości przekazywanej do methody klasowej

witam
mam metode klasową, w klasie Task, powiedzmy

def self.parse_foo(foo) foo["fffff"] = "gggg" foo end
otóż po wywołaniu tej metody przykładowo

bar = {"aaaa" => "bbbb"} ret = Task.parse_foo(bar)
zmieniana jest także wartość parametru bar, tak jakby była przekazywana przez referencje a nie wartość. dlaczego tak się dzieje i jak tego uniknąć ? dodam że jeśli zrobie to samo dla cyfr a nie dla hashy metoda zachowuje sie normalnie.

Bo w rubym zmienne są przekazywane właśnie przez referencję. Możesz użyć metody clone (ale uważaj na zagnieżdzone hashe, wtedy musisz użyć np ActiveSupportowego deep dup)

Dzieje się tak dlatego, że wykonujesz metodę, która zmienia obiekt. Tak samo się stanie jeżeli użyjesz << na stringu.

[code]def foo(bar)
bar << “…”
end

baz = “Baz”
foo(baz)

baz #=> “Baz…”[/code]
Możesz tego uniknąć używając np. clone lub tworząc nowego hasha, w którym będziesz zapisywał to czego potrzebujesz.

slawosz: rozumiem, ale dlaczego dla liczb były przekazywane przez wartość ?
drogus, slawosz: dzięki, clone pomogło.

Bo nie wszystkie obiekty w Ruby są Mutable.

W Rubym parametry przekazywane są przez wartość a nie przez referencje.

clone zadziałało, nawet na zagnieżdzonym hashu, natomiast deep_dup zwraca undefined method `deep_dup’ for #Hash:0x7f20add8e0f8

To trochę bardziej skomplikowane, zasadniczo nieprawda :stuck_out_tongue:

To nie jest skomplikowane, chociaż wiem do czego dążysz. Nie zmieni to jednak faktu, że w rubim zmienne są przekazywane przez wartość. Gdyby były przekazywane przez referencje to poniższy program:

[code]def swap(a, b)
a, b = b, a
end

a, b = “foo”, “bar”
swap(a, b)
puts [a, b].join(" ")[/code]
wypisałby “bar foo”, a wypisuje “foo bar”. Natomiast to, że wewnętrznie przekazywaną wartością jest wskaźnik (referencja) do obiektu (ale nie do zmiennej), tylko że programista tego nie widzi, powoduje, że ludzie błędnie sądzą, że iż jest to referencja do zmiennej.

W c++ wskaźniki przekazywane są przez wartość i nie przeszkadza to na wewnętrzną zmianę reprezentacji obiektu na który wskazują.

Tudzież jestem w stanie zgodzić się na stwierdzenie, że zmienne przekazywane są przez wartość, a ich wartością jest referencja do obiektu (nie jest to jednak równoważne z przekazywanie przez referencje).

Mówiąc po prostu, że parametry są przekazywane przez wartość, jesteś tak samo precyzyjny, jakbyś powiedział, że są przekazywane przez referencję. I jedno i drugie bez dokładniejszego wyjaśnienia nie jest prawdą :smiley:

Panowie, jeśli twierdzicie inaczej to podajcie jakieś przykłady bo jak dla mnie wasze “kontrargumenty” są żadne.
Odpowiedzcie proszę na pytanie.

a = "foo"

Co zawiera zmienna a?

I nie jest to tak samo równoważne przekazywaniu przez wartość bo to nie wartość obiektu jest przekazywana tak jak w przypadku typów primitive. Jeżeli chodzi o tą kwestię to zamiast ograniczać się do stwierdzeń przez wartość/przez referencję, wolę zwyczajnie powiedzieć “przez kopię referencji” :wink:

Całkiem niedawno już taka dyskusja była:
http://rubyonrails.pl/forum/t4263-Modyfikacja-parametru-metody.

I nie jest to tak samo równoważne przekazywaniu przez wartość bo to nie wartość obiektu jest przekazywana tak jak w przypadku typów primitive. Jeżeli chodzi o tą kwestię to zamiast ograniczać się do stwierdzeń przez wartość/przez referencję, wolę zwyczajnie powiedzieć “przez kopię referencji” ;)[/quote]
Jest równoważne jeśli odpowiesz poprawnie na postawione wcześniej przeze mnie pytanie (“Co zawiera zmienna a?”).

Btw, nie napisałem, że przekazywana jest wartość obiektu. Przekazywana jest wartość zmiennej.

[quote=radarek]Jest równoważne jeśli odpowiesz poprawnie na postawione wcześniej przeze mnie pytanie (“Co zawiera zmienna a?”).

Btw, nie napisałem, że przekazywana jest wartość obiektu. Przekazywana jest wartość zmiennej.[/quote]
Ok… co zawiera zmienna a? yyyyy wartość “foo”? :wink:
Komplikujesz trochę wprowadzając taki termin jak wartość zmiennej, który wg Ciebie nie jest tym samym co wartość obiektu.
Jeżeli masz po prostu na myśli to, że przez wartość przekazywane są referencje obiektów, a nie same obiekty to chyba sie rozumiemy :wink:

Wprowadzam pojęcie wartość zmiennej, gdyż coś przecież ta zmienna musi zawierać :). Zmienna a nie zawiera “foo”, jest tylko do niej odniesieniem (referencją, ukrytym wskaźnikiem).

A co się dzieje gdy robisz:

a = "foo" b = a
? Ano do zmiennej b przypisujesz wartość zmiennej a (w skrócie mówimy do zmiennej b przypisujemy zmienną a). Dokładnie to samo dzieje się gdy przekazujesz zmienną jako parametr do metody.

Co do referencji, tych znanych z c++ (bo chyba to jest typowy przykład języka, który takie referencje obsługuje?), w rubym nie zrobisz czegoś takiego:

[code=c++]#include

int main() {
int a = 123;
int &b = a;

b = 255;
printf("%d\n", a); // wypisze 255
return 0;
}[/code]
Właśnie dlatego, że zmienna nie może być referencją do drugiej zmiennej, a także dlatego, że zmienne nie są przekazywane przez referencje jako parametry metod.

Poczytajcie sobie http://www.khelll.com/blog/ruby/ruby-pass-by-value-or-by-reference/

Oczywiście znajdą się śmiałkowie twierdzący, że jest inaczej, jak to w życiu ;-).

I jeszcze jedno. To, że wartościami zmiennych są referencje, nie znaczy, że same zmienne są przekazywane przez referencje.

Ależ wszystko sie zgadza radarek :slight_smile: Tylko zobacz ile się trzeba tłumaczyć z takiego stwierdzenia, że parametry są przekazywane przez wartość, które jest poprawne, ALE ALE ALE tak na prawdę parametr nie jest tym czym myślisz, że jest (bo jak się okazuje - nie Twoim obiektem). Taka pół prawda wg mnie mąci tak samo w głowie jak historie o przekazywaniu przez referencje :wink: I tylko do tego mam w tym wątku zastrzeżenia :wink:

Ja rozumiem, że łatwiej jest powiedzieć “parametry są przekazywane przez referencje”, tylko, że to nie jest prawda, więc po co kłamać?:slight_smile:

Tak samo Ty kłamiesz twierdząc że parametry są przekazywane przez kopię.

Tomash, a przez co są przekazywane?