Che cos'è una variabile? (o anche "passaggio by-? in Python")

Messaggioda marco2132k » 06/01/2020, 00:53

Ciao.

1) Per il linguaggio C++ (o in C) che cos'è una variabile? (mi interessa capirlo "a basso livello"). In altre parole, mi rimbomba nella testa che "le istanze di tipi primitivi sono storate nello stack, mentre gli oggetti più complessi possono essere messi nello heap", ma che significa esattamente ciò? La riga di codice int p = 0; "dichiara e inizializza una variabile" p: posso vedere p esattamente come il numero 0? O è più giusto pensare a essa come ad un contenitore per l'indirizzo di un oggetto 0 nello stack? (Non mi pare di ricordare di "un'indirizzo di una cosa nello stack", però...).

2) Che accade in Java? Per quanto ne so, le variabili lì sono effettivamente dei contenitori per un indirizzo, di una cosa che però è automaticamente storata nel posto più consono (secondo il compilatore, non secondo il programmatore). Se però consideriamo le chiamate dei metodi
Codice:
public static void foo_1(Foo f) {
  f = new Foo();
}

Codice:
public static void foo_2(Foo f) {
  f.fuckUp();
}

su un oggetto di tipo Foo avente un metodo fuckUp abbastanza autoesplicativo, ad esempio come
Codice:
Foo f = new Foo();
foo_1(f);
// f è ancora lo stesso di prima
// ma...
foo_2(f);
// ...ora no >:S

ci accorgiamo di alcune stranezze. Il motivo di tali è la scelta progettuale di nascondere i puntatori e gli operatori * e -> di dereference; più il fatto che i riferimenti in stile C++ in Java non ci sono: il che rende "strano" il comportamento di cose passate by-value (unica "modalità di passaggio" di cui Java dispone, in ogni caso). Sbaglio? È per questo che certe persone inveiscono contro chi usa il termine "puntatore", riguardo a Java?

3) Veniamo a Python (2.7). Non mi è molto chiara la cosa. Il prof. non vuole sentir chiamare le variabili "variabili" (tantomeno "puntatori"), ma "riferimenti". Mi sembra però che Python non superi lo swap-test (non posso definire una funzione swap che (pseudocodice)
Codice:
swap(a,b) {
  tmp = a
  a = b
  b = tmp
}

a, b = 10,57
swap(a,b)
// a,b sono ora 57,10
)

Questa cosa si può fare eccome in C++:
Codice:
void swap(Foo& a, Foo& b) {
  Foo tmp = a;
  a = b;
  b = tmp;
}

appunto perché in C++ esistono i riferimenti (o alias) veri, non come in Java. E in Python, cosa sono le variabili (o chi per loro)?

(scusate per gli abusi di linguaggio: è da un sacco che non tocco queste cose).
marco2132k
Average Member
Average Member
 
Messaggio: 466 di 528
Iscritto il: 18/02/2018, 23:52

Re: Che cos'è una variabile? (o anche "passaggio by-? in Python")

Messaggioda probid » 06/01/2020, 07:33

ma che significa esattamente ciò? La riga di codice int p = 0; "dichiara e inizializza una variabile" p: posso vedere p esattamente come il numero 0?
O è più giusto pensare a essa come ad un contenitore per l'indirizzo di un oggetto 0 nello stack?


Il compilatore mantiene una tabella dei simboli: quando incontra per la prima volta una dichiarazione, crea un'associazione tra l'identificatore e l'indirizzo di memoria corrispondente. Dopodichè ogni occorrenza dell'identificatore nel codice viene sostituita con il relativo indirizzo.
Quindi una variabile non è il contenitore di un indirizzo, ma ne è un'alias.
Nel caso in cui la variabile sia di tipo puntatore, però, sarà sempre un nome associato alla relativa area di memoria,
ma questa avrà all'interno a sua volta un indirizzo: puoi quindi vederla effettivamente come un contenitore.

Ora, quello che credo ti crei confusione è che il concetto di riferimento in C++ è differente rispetto a quello di Java e Python.
Nel primo è un nome alternativo associato ad una variabile e puoi pensarlo come un'altra entry nella tabella detta sopra, quindi passarlo a foo_1() sarebbe come riferirsi alla variabile originaria; nel secondo è qualcosa di molto simile ad un puntatore. Ipotizzando di voler far funzionare foo_1() in C, che al contrario di C++ non ha il tipo riferimento, sarebbe necessario un puntatore a puntatore. Facendo il parallelo con Java, ci mancherebbe un livello di indirizzamento.


ci accorgiamo di alcune stranezze.

Non ho capito perchè parli di stranezze, è il comportamento normale del passaggio per valore. Dovrebbe essere così anche in C++, se non usi i riferimenti.

È per questo che certe persone inveiscono contro chi usa il termine "puntatore", riguardo a Java?

Chi contesta il termine si riferisce probabilmente ad alcune limitazioni rispetto ai puntatori di C/C++: niente aritmetica o conversioni numeriche, e forse alcune caratteristiche oscure di cui non sono al corrente. D'altronde, l'eccezione NullPointerException su un riferimento nullo suggerisce che ci sia almeno una qualche affinità :)

Il prof. non vuole sentir chiamare le variabili "variabili" (tantomeno "puntatori"), ma "riferimenti". [...] E in Python, cosa sono le variabili (o chi per loro)?


In Java le variabili possono essere di un tipo primitivo (int, double, ...) o un riferimento ad un oggetto. In Python tutto è un oggetto, anche un intero. Quindi tutte le variabili sono riferimenti.
probid
Starting Member
Starting Member
 
Messaggio: 37 di 40
Iscritto il: 01/10/2010, 19:30

Re: Che cos'è una variabile? (o anche "passaggio by-? in Python")

Messaggioda marco2132k » 06/01/2020, 12:50

Grazie per la risposta!

probid ha scritto:Il compilatore mantiene una tabella dei simboli
Ok. Mi è più chiaro.

probid ha scritto:Non ho capito perchè parli di stranezze, è il comportamento normale del passaggio per valore. Dovrebbe essere così anche in C++, se non usi i riferimenti.
Le ho chiamate "stranezze" perché il comportamento dei metodi foo_1 e foo_2 non è coerente con il fatto che Foo f = new Foo();, in Java, è un puntatore (o qualcosa di molto molto simile). Considera quello che succederebbe in C++: quali tra questi metodi si comportano come l'analogo in Java?
Codice:
void foo_1(Foo* f) {
  f = new Foo();
}

void foo_2a(Foo* f) {
  f.fuckUp();
}

void foo_2b(Foo* f) {
  f->fuckUp();
}


Sono foo_1 e foo_2b (mentre foo_2a, che mi auguro non abbia senso nemmeno in C++, è scritto esattamente come se stessi digitando codice Java). Se i riferimenti di Java (o di Python, in base a quanto ho capito) fossero riferimenti veri, un chiamata a foo_1 avrebbe effetti collaterali (e invece non ne ha). Se i puntatori di Java fossero veri puntatori, non dovrebbe essere nemmeno possibile chiamare foo_2a (perché, in genere, un puntatore non ha un metodo fuckUp().

Il punto è che posso dire lo stesso in Python (ho appena provato con una lista e il suo metodo pop). Mi confermi che il comportamento delle "variabili" in Python è esattamente lo stesso che in Java, ossia quello di "puntatori" senza aritmetica dove non c'è mai bisogno di dereference (dei * e -> C++-like)?

(Abbi pietà: ho ripreso in mano queste cose ieri sera, dopo tre anni che le ignoravo felicemente :-D )
marco2132k
Average Member
Average Member
 
Messaggio: 467 di 528
Iscritto il: 18/02/2018, 23:52

Re: Che cos'è una variabile? (o anche "passaggio by-? in Python")

Messaggioda Sergio » 06/01/2020, 21:55

marco2132k ha scritto:1) Per il linguaggio C++ (o in C) che cos'è una variabile? (mi interessa capirlo "a basso livello"). In altre parole, mi rimbomba nella testa che "le istanze di tipi primitivi sono storate nello stack, mentre gli oggetti più complessi possono essere messi nello heap", ma che significa esattamente ciò? La riga di codice int p = 0; "dichiara e inizializza una variabile" p: posso vedere p esattamente come il numero 0? O è più giusto pensare a essa come ad un contenitore per l'indirizzo di un oggetto 0 nello stack? (Non mi pare di ricordare di "un'indirizzo di una cosa nello stack", però...).

Proviamo a distinguere:
a) Variabili globali e variabili statiche. Quando un programma viene caricato in memoria per poterlo eseguire, vengono caricate sia le istruzioni che le variabili globali e statiche. Il nome di una di queste variabili non è altro che un alias per l'indirizzo di memoria in cui viene conservato il loro valore, un indirizzo che non cambia mai durante l'esecuzione.
b) Variabili locali e parametri. Quando viene eseguita una funzione, i suoi parametri e poi le variabili locali vengono caricati nello stack, insieme all'indirizzo a cui la funzione deve tornare dopo l'esecuzione. Se i parametri vengono passati per valore, nello stack viene copiato il loro valore; se vengono passati per riferimento, nello stack viene copiato il loro indirizzo. Conseguenza: nel primo caso, se la funzione cambia il valore di un parametro il cambiamento non ha alcun effetto sulla variabile passata come parametro, nel secondo quando la funzione cambia il valore il cambiamento ha effetto sulla variabile passata come parametro. I nomi dei parametri passati per valore e delle variabili locali sono ancora alias per indirizzi di memoria, ma ora questa memoria è lo stack e quando la funzione giunge al termine dell'esecuzione e torna al codice che l'aveva chiamata lo stack viene liberato, non ne rimane traccia e quegli alias (peraltro non più utilizzabili) perdono ogni significato.
c) Variabili allocate dinamicamente. Si può allocare dinamicamente memoria e riferirsi ad essa tramite puntatori. Si dice che la memoria allocata viene ricavata dallo heap. Un puntatore svolge un ruolo analogo a quello del nome di una variabile globale o statica, nel senso che è un alias per un indirizzo di memoria. La differenza è che la memoria per le variabili dinamiche non è allocata una volta per tutte all'inizio dell'esecuzione e, durante l'esecuzione, può essere deallocata (i puntantori non puntano più a nulla), riallocata, aumentata ecc.
Per una descrizione della differenza tra stack e heap puoi vedere qui.

Tutto quanto sopra è molto generico, perché quello che accade in concreto e in dettaglio dipende dal processore, dal sistema operativo e soprattutto dal linguaggio usato. E qui veniamo a....

marco2132k ha scritto:Mi sembra però che Python non superi lo swap-test (non posso definire una funzione swap che (pseudocodice)
Codice:
swap(a,b) {
  tmp = a
  a = b
  b = tmp
}

a, b = 10,57
swap(a,b)
// a,b sono ora 57,10
)

Questa cosa si può fare eccome in C++:
Codice:
void swap(Foo& a, Foo& b) {
  Foo tmp = a;
  a = b;
  b = tmp;
}

In C++ la funzione... funziona perché passi i parametri per riferimento. In Python questo non è possibile, perché in Python non c'è la possibilità di passare esplicitamente indirizzi di variabili.
Questo non vuol dire che non ci siano soluzioni. La gamma delle soluzioni possibili è riepilogata qui e la più semplice è:
Codice:
>>> def swap0(a, b):
...   return b, a
...
>>> swap0(1,2)
(2, 1)
D'altra parte, in Python si distingue tra oggetti "mutable" e "immutable": se passi a una funzione un oggetto "mutable", come una lista, in realtà passi un riferimento e la lista può essere cambiata dalla funzione.
Esempio molto banale:
Codice:
>>> def swaplist(l):
...   temp = l[0]
...   l[0] = l[1]
...   l[1] = temp
...   return l
...
>>> swaplist([1,2])
[2, 1]

In Java le cose sono analoghe, perché i parametri sono sempre passati per valore, nel senso che non puoi passare un puntatore, ma se quella che viene passata non è una variabile appartenente a un tipo primitivo, ma una variabile allocata dinamicamente, il "valore" che viene passato è il suo indirizzo. Maggiori dettagli qui.
"Se vuoi un anno di prosperità coltiva del riso. Se vuoi dieci anni di prosperità pianta degli alberi. Se vuoi cento anni di prosperità istruisci degli uomini" (proverbio cinese). E invece... viewtopic.php?p=236293#p236293
Avatar utente
Sergio
Cannot live without
Cannot live without
 
Messaggio: 6313 di 6712
Iscritto il: 26/04/2004, 10:56
Località: Roma

Re: Che cos'è una variabile? (o anche "passaggio by-? in Python")

Messaggioda marco2132k » 08/01/2020, 17:30

Sergio ha scritto:Maggiori dettagli qui.
Stavo cercando esattamente di capire meglio la discussione a quel link.

Mi incasina che né in Java né in Python ci sia un distinzione "morfologica" tra "variabili" (o chi per loro) e "puntatori" (o chi per loro), e che i riferimenti non abbiano nulla a che vedere con i riferimenti C++-like.

Credo di aver chiarito, comunque. Però devo vedermi meglio la storia sugli immutable objects in Python. (E non ha senso che inizi a parlarne ora perché dire cavolate :-D )
marco2132k
Average Member
Average Member
 
Messaggio: 471 di 528
Iscritto il: 18/02/2018, 23:52

Re: Che cos'è una variabile? (o anche "passaggio by-? in Python")

Messaggioda marco2132k » 08/01/2020, 17:30

Sergio ha scritto:Maggiori dettagli qui.
Stavo cercando esattamente di capire meglio la discussione a quel link.

Mi incasina che né in Java né in Python ci sia un distinzione "morfologica" tra "variabili" (o chi per loro) e "puntatori" (o chi per loro), e che i riferimenti non abbiano nulla a che vedere con i riferimenti C++-like.

Credo di aver chiarito, comunque. Però devo vedermi meglio la storia sugli immutable objects in Python. (E non ha senso che inizi a parlarne ora perché direi cavolate :-D )
marco2132k
Average Member
Average Member
 
Messaggio: 471 di 528
Iscritto il: 18/02/2018, 23:52


Torna a Informatica

Chi c’è in linea

Visitano il forum: Nessuno e 13 ospiti