Assegnazione multipla, differenze confuse

Qualcuno sa perchè gli array utilizzano la stessa area di memoria negli
assegnamenti multipli? Non apprezzo questo genere di diversità che a mio
avviso non fanno altro che generare confusione:

Esempio:
#String
irb(main):013:0> a=b=""
=> “”
irb(main):014:0> a
=> “”
irb(main):015:0> b
=> “”
irb(main):016:0> a=“a”
=> “a”
irb(main):017:0> a
=> “a”
irb(main):018:0> b
=> “”
irb(main):019:0> b=“b”
=> “b”
irb(main):020:0> a
=> “a”
irb(main):021:0> b
=> “b”

#Fixnum
irb(main):033:0> a=b=0
=> 0
irb(main):034:0> a
=> 0
irb(main):035:0> b
=> 0
irb(main):036:0> a=1
=> 1
irb(main):037:0> a
=> 1
irb(main):038:0> b
=> 0

#Array
irb(main):039:0> a = b = []
=> []
irb(main):040:0> a=b=[]
=> []
irb(main):041:0> a
=> []
irb(main):042:0> b
=> []
irb(main):043:0> a<<“a”
=> [“a”]
irb(main):044:0> a
=> [“a”]
irb(main):045:0> b
=> [“a”]
irb(main):046:0> b<<“b”
=> [“a”, “b”]
irb(main):047:0> a
=> [“a”, “b”]
irb(main):048:0> b
=> [“a”, “b”]
irb(main):049:0> a.push “aa”
=> [“a”, “b”, “aa”]
irb(main):050:0> a
=> [“a”, “b”, “aa”]
irb(main):051:0> b
=> [“a”, “b”, “aa”]
irb(main):052:0>

sia con String che con Fixnum, in caso di assegnamento multiplo stai
usando
comunque la stessa zona di memoria :wink:

a = b = [] # => []
a.object_id # => 6836120
b.object_id # => 6836120

c = d = ‘’ # => “”
c.object_id # => 5786700
d.object_id # => 5786700

solo che con Array, hai usato il metodo ‘<<’ che va a modificare lo
stesso
oggetto, e non restituisce una sua copia che punta ad una zona
differente.

nel tuo caso, con le stringhe hai fatto puntare “a” e “b” a due oggetti
differenti nel momento in cui hai fatto l’assegnamento:

a = b = ‘’
a.object_id == b.object_id # => true
a = “a” # => “a”
a.object_id == b.object_id # => false

ora proviamo ad usare “<<” :slight_smile:

a = b = ‘’
a.object_id == b.object_id # => true
a << “a” # => “a”
a.object_id == b.object_id # => true

se ripeti le stesse operazioni con gli Array, vedrai lo stesso
comportamento :wink:

ciao,
A.

Il 12/03/2012 15:40, Marco M. ha scritto:

On Mar 12, 2012, at 3:40 PM, Marco M. wrote:

Qualcuno sa perch gli array utilizzano la stessa area di memoria negli
assegnamenti multipli? Non apprezzo questo genere di diversit che a mio
avviso non fanno altro che generare confusione:

Le stringhe sono immutabili: quando assegni ‘a’ stai assegnando un
oggetto nuovo.
Gli array sono container, quando aggiungi un elemento lo stai
aggiungendo all’oggetto iniziale, ma l’oggetto e’ sempre quello.

ngw

Il 12/03/2012 16:33, Nicholas W. ha scritto:

Le stringhe sono immutabili: quando assegni ‘a’ stai assegnando un oggetto
nuovo.
Gli array sono container, quando aggiungi un elemento lo stai aggiungendo
all’oggetto iniziale, ma l’oggetto e’ sempre quello.

attenzione, “aggiungere” non significa “assegnare”. le operazioni di
seguito
posso eseguirle con un Array, ed otterrei lo stesso comportamento:

a = ‘’
a.object_id # 22184940
a << ‘a’
a.object_id # 22184940
a[0] = ‘b’
a.object_id # 22184940

a = ‘a’
a.object_id # 22099640

On Mar 12, 2012, at 4:33 PM, Nicholas W. wrote:

On Mar 12, 2012, at 3:40 PM, Marco M. wrote:

Qualcuno sa perch gli array utilizzano la stessa area di memoria negli
assegnamenti multipli? Non apprezzo questo genere di diversit che a mio
avviso non fanno altro che generare confusione:

Le stringhe sono immutabili: quando assegni ‘a’ stai assegnando un oggetto
nuovo.
Gli array sono container, quando aggiungi un elemento lo stai aggiungendo
all’oggetto iniziale, ma l’oggetto e’ sempre quello.

P.S.

a = b = ‘’
=> “”
a << ‘a’
=> “a”
b
=> “a”
a = b = ’ HA! ’
=> " HA! "
a.strip!
=> “HA!”
b
=> “HA!”

Magari e’ piu’ chiaro.

ngw


[ 926381, 23200231779, 1299022, 1045307475 ].collect { |a| a.to_s( 36 )
}.join( " " )
Nicholas W. (ngw)
[email protected]

On Mar 12, 2012, at 5:06 PM, Andrea P. wrote:

Il 12/03/2012 16:33, Nicholas W. ha scritto:

Le stringhe sono immutabili: quando assegni ‘a’ stai assegnando un oggetto
nuovo.

Gli array sono container, quando aggiungi un elemento lo stai aggiungendo
all’oggetto iniziale, ma l’oggetto e’ sempre quello.

attenzione, “aggiungere” non significa “assegnare”. le operazioni di seguito
posso eseguirle con un Array, ed otterrei lo stesso comportamento:

E che ho detto io ? :stuck_out_tongue:

ngw

2012/3/12 Nicholas W. [email protected]:

On Mar 12, 2012, at 5:06 PM, Andrea P. wrote:

Il 12/03/2012 16:33, Nicholas W. ha scritto:

Le stringhe sono immutabili: quando assegni ‘a’ stai assegnando un oggetto
nuovo.
Gli array sono container, quando aggiungi un elemento lo stai aggiungendo
all’oggetto iniziale, ma l’oggetto e’ sempre quello.

attenzione, “aggiungere” non significa “assegnare”. le operazioni di seguito
posso eseguirle con un Array, ed otterrei lo stesso comportamento:

E che ho detto io ? :stuck_out_tongue:

che sono immutabili, ma non sono immutabili, stai pensando a python
(cough java cough :slight_smile:

Il problema originale dell’OP che da una parte usa = come
assegnazione e dall’altra muta l’oggetto, ma poteva farlo pure con una
stringa, come dimostra Andrea :slight_smile:


twitter: @riffraff
blog (en, it): www.riffraff.info riffraff.blogsome.com
work: cascaad.com circleme.com

Come al solito ha ragione ruby, bastava ragionarci un pò. Siete troppo
avanti! Poi facevo le prove sul singolo elemento di un array:

irb(main):397:0> c=d=[]
=> []
irb(main):398:0> c.object_id==d.object_id
=> true
irb(main):399:0> c[0]=0
=> 0
irb(main):400:0> c
=> [0]
irb(main):401:0> d
=> [0]
irb(main):402:0> d<<1
=> [0, 1]
irb(main):403:0> c
=> [0, 1]
irb(main):404:0> d
=> [0, 1]
irb(main):405:0> c.object_id==d.object_id
=> true
irb(main):406:0> d=[0,1]
=> [0, 1]
irb(main):407:0> c
=> [0, 1]
irb(main):408:0> c.object_id==d.object_id
=> false

Visto che siamo in tema e mi sento abbastanza rompipalle, non trovate
che il metodo sub! sia un pò pericoloso? Capisco che i dati vengono
passati per riferimento ma modifica il valore oltre lo scope:

def upd(str)
str.sub! /./, “Tie!”
end

irb(main):414:0> a
=> “Tie!”
irb(main):415:0> a=‘a’
=> “a”
irb(main):416:0> upd(a)
=> “Tie!”
irb(main):417:0> a
=> “Tie!”

Il 12/03/2012 16:35, Luigi P. ha scritto:

afaik per assegnamento multiplo si intende questo:

a, b = [ [], [] ]

pardon, ho sbagliato termine, grazie per la correzione :stuck_out_tongue:

Conosco la convenzione, era solo per fare un pò di salotto (ricordo che
ne avevamo discusso anche qualche tempo fa). Se si conosce alla
perfezione un linguaggio non si commettono errori di questo tipo, la
questione è la probabilità di commetterli:

def qualcosa(str)
#…
str.upcase!
str << " TIE!"
#…
end

irb(main):563:0> nome=“peppino”
=> “peppino”
irb(main):564:0> frase=qualcosa(nome)
=> “PEPPINO TIE!”
irb(main):565:0> frase
=> “PEPPINO TIE!”
irb(main):566:0> nome
=> “PEPPINO TIE!”

Certamente basterebbe usare il metodo senza ! che con l’assegnazione
creerebbe uno nuovo oggetto:

str = str.upcase

ma l’errore nasce dal fatto che la variabile è passata per riferimento,
infatti l’uso del ! è solitamente intenzionale.
In ruby non si può passare una variabile per valore, l’unico modo è
farlo manualmente, clonandola nel caso delle stringhe o altro metodo
analogo:

def qualcosa(str)
str = str.clone
#…
str.upcase!
str << " TIE!"
#…
end

irb(main):577:0> nome=“peppino”
=> “peppino”
irb(main):578:0> frase=qualcosa(nome)
=> “PEPPINO TIE!”
irb(main):579:0> frase
=> “PEPPINO TIE!”
irb(main):580:0> nome
=> “peppino”

La classe fixnum invece e ad esempio è immutabile quindi per i numeri il
funzionamento cambia:

def qualcosa(o)
#…
o << 1
#…
end

irb(main):595:0> num=2
=> 2
irb(main):596:0> qualcosa num
=> 4
irb(main):597:0> num
=> 2

Con gli array invece il funzionamento torna ad essere simile alle
stringhe:

irb(main):598:0> ar=[]
=> []
irb(main):599:0> qualcosa ar
=> [1]
irb(main):600:0> ar
=> [1]

Probabilmente è poco oggettivo ma secondo me qualche confusione la crea.
La versione 2.0 è sempre più vicina ed al momento non mi risulta che
verrà alterato niente sulla questione ma se dovessero fare qualche
sondaggio io probabilmente chiederei questo.
In ogni caso si tratta di piccolezze in confronto gli enormi pregi di
ruby.

Il 13/03/2012 17:45, Marco M. ha scritto:

Visto che siamo in tema e mi sento abbastanza rompipalle, non trovate
che il metodo sub! sia un p pericoloso? Capisco che i dati vengono
passati per riferimento ma modifica il valore oltre lo scope:

def upd(str)
str.sub! /./, “Tie!”
end

stai usando “sub!”, per convenzione i metodi con un punto esclamativo
vanno a
modificare internamente l’oggetto. prova “sub” ed otterrai una copia :wink:

On Mar 14, 2012, at 11:11 AM, Andrea P. wrote:

Il 14/03/2012 09:57, Marco M. ha scritto:

Certamente basterebbe usare il metodo senza ! che con l’assegnazione
creerebbe uno nuovo oggetto:

esatto, non capisco il punto di questa discussione. se qualcuno fa copia/incolla
dalla rete senza sapere che esistono metodi distruttivi e non, normale commettere
errori, ma credo che sarebbe il punto meno importante :wink:

Anche perche’ piu’ esplicito di un punto esclamativo non credo esista
molto. Forse “WARNING!RICKROLLD!strip!”.

ngw

Il 14/03/2012 09:57, Marco M. ha scritto:

Conosco la convenzione, era solo per fare un p di salotto (ricordo che
ne avevamo discusso anche qualche tempo fa). Se si conosce alla
perfezione un linguaggio non si commettono errori di questo tipo, la
questione la probabilit di commetterli:

imho, la probabilit di commettere errori di questo tipo inversamente
proporzionale alla quantit di studio ed esercizio che applichi :wink:

Certamente basterebbe usare il metodo senza ! che con l’assegnazione
creerebbe uno nuovo oggetto:

esatto, non capisco il punto di questa discussione. se qualcuno fa
copia/incolla
dalla rete senza sapere che esistono metodi distruttivi e non, normale
commettere errori, ma credo che sarebbe il punto meno importante :wink:

ma l’errore nasce dal fatto che la variabile passata per riferimento,
infatti l’uso del ! solitamente intenzionale.

non un errore, semplicemente che in ruby tutto un oggetto, che
senso ha
passare valori? per questo che spesso esistono due versioni dello
stesso metodo.

In ruby non si pu passare una variabile per valore, l’unico modo
farlo manualmente, clonandola nel caso delle stringhe o altro metodo
analogo:

again, che senso ha clonare esplicitamente, se basta usare un metodo non
distruttivo che restituisce una nuova istanza dell’oggetto?

La classe fixnum invece e ad esempio immutabile quindi per i numeri il
funzionamento cambia:

si immutabile, nel senso che conserva il valore direttamente dentro la
variabile anzich un puntatore (reference). i metodi chiamati da Fixnum
non
restituiscono una copia, ma una rappresentazione del numero, questo
perch non
possono esistere pi istanze dello stesso numero (un po’ come i
Singleton):

a = 1
a.object_id == a.object_id # true

Con gli array invece il funzionamento torna ad essere simile alle
stringhe:

sia String che Array sono container di altri oggetti. inoltre a basso
livello
non esistono rappresentazioni per le stringhe e gli array, al contrario
degli
integer.

Probabilmente poco oggettivo ma secondo me qualche confusione la crea.

come con altri linguaggi e/o tecnologie, senza conoscere quello che stai
facendo, inevitabile commettere errori e confusioni :wink:

A.

Il 14/03/2012 16:45, Marco M. ha scritto:

non un errore, semplicemente che in ruby tutto un oggetto, che
senso ha
passare valori? per questo che spesso esistono due versioni dello
stesso metodo.

ha senso per gli oggetti che hanno un valore come i tipi dato

ed infatti ti ho citato il caso particolare di Fixnum, che comunque
viene
trattato come un oggetto. forse mi perdo qualcosa io, ma non mi risulta
che
esistono i tipi di dato in Ruby :wink:

again, che senso ha clonare esplicitamente, se basta usare un metodo non
distruttivo che restituisce una nuova istanza dell’oggetto?

per una questione di sicurezza, non sempre sai cosa verr usato
all’interno di un metodo, in un linguaggio dinamico come ruby poi

non sono d’accordo. in quanto programmatore, hai la resposabilit di
sapere cosa
stai combinando con il codice. se un metodo distruttivo, c’ la
convenzione
del “!”. e tutto torna :wink:

come con altri linguaggi e/o tecnologie, senza conoscere quello che stai
facendo, inevitabile commettere errori e confusioni :wink:

infatti, come ho scritto prima: tutti possono sbagliare, solo una
questione di probabilit, una componente legata alla persona, un’altra
senza dubbio allo strumento.

tutto questo mi ricorda un tizio che scrisse ~10MB di javascript su IE6.
quando
uscito IE7 ha sostenuto che il browser era buggato perch non
“funzionava pi
niente” >:-]

Andrea P. wrote in post #1051399:

Il 14/03/2012 09:57, Marco M. ha scritto:

imho, la probabilit di commettere errori di questo tipo inversamente
proporzionale alla quantit di studio ed esercizio che applichi :wink:

E’ vero ma ogni linguaggio ha una capacità diversa di attrarre errori,
c’è poi il programmatore che quando si trova nella stagione degli amori
introduce un consistente moltiplicatore

esatto, non capisco il punto di questa discussione. se qualcuno fa
copia/incolla
dalla rete senza sapere che esistono metodi distruttivi e non, normale
commettere errori, ma credo che sarebbe il punto meno importante :wink:

non credo ci sia un punto, era solo per trascorrere un pò di tempo in
questioni filosofiche

non un errore, semplicemente che in ruby tutto un oggetto, che
senso ha
passare valori? per questo che spesso esistono due versioni dello
stesso metodo.

ha senso per gli oggetti che hanno un valore come i tipi dato

again, che senso ha clonare esplicitamente, se basta usare un metodo non
distruttivo che restituisce una nuova istanza dell’oggetto?

per una questione di sicurezza, non sempre sai cosa verrà usato
all’interno di un metodo, in un linguaggio dinamico come ruby poi

come con altri linguaggi e/o tecnologie, senza conoscere quello che stai
facendo, inevitabile commettere errori e confusioni :wink:

infatti, come ho scritto prima: tutti possono sbagliare, è solo una
questione di probabilità, una componente è legata alla persona, un’altra
senza dubbio allo strumento.