[Python] 0 in (False,) // 0 == False

Enrico Franchi enrico.franchi a gmail.com
Ven 12 Feb 2010 19:59:22 CET


On Feb 11, 2010, at 12:24 AM, Pietro Battiston wrote:

> Quando si parla di vantaggi concreti, preferisco farlo davanti a dati
> concreti.

Che sarebbero? 

> Ovviamente non intendevo che l'aritmetica possa esistere senza
> uguaglianza, ma che il simbolo "=" può essere definito ben a monte
> dell'aritmetica, in maniera vagamente simmetrica a quel che succede
> appunto nel Python.

Probabilmente diamo dunque un differente significato al concetto di
"non avere niente a che fare". Comunque una volta che siamo in accordo,
tutto bene.

Poi ovviamente si, sono d'accordo che un uguaglianza possa stare a monte
dell'aritmetica (uguaglianza semantica, intendo, l'uguaglianza sintattica e' una bestia
ancora diversa).

Anche l'uguaglianza di python e', ovviamente potenzialmente semantica. Sebbene il default
di object sia la versione ad oggetti dell'uguaglianza sintattica, ovvero la 
completa identita', di fatto poi == e' ridefinito per vaste classi di oggetti. 
Suppongo che su sta roba siamo tutti d'accordo e non
sia necessario soffermarci oltre.

> Se le tue intuizioni informatiche sono azzeccate quanto quelle
> personali, non mi stupisce la confusione che fai parlandone.

Ottimo. Allora ci hai lavorato anche tu e dovresti essere piuttosto consapevole
del fatto che definire formalmente un metodo di un oggetto di un linguaggio
completamente dinamico sia un lavoraccio, visto che hai la *semantica* che
dipende dall'esecuzione, visto che quale codice venga chiamato da una data
chiamata di funzione (o anche solo da un accesso a membro) e' potenzialmente
non noto a compile time.

Anche immaginando un == scritto "staticamente" c' da fare un discreto lavoro
per formalizzare il tutto. E non credo che la cosa ci porti da nessuna parte,
ma se vuoi iniziare ti seguo e vediamo di metterla in piedi.

> 
> (N.B: non risponderò in maniera polemica a parti della tua email che non
> siano gratuitamente polemiche. Anzi, facciamo che alle altre parti
> gratuitamente polemiche non rispondo proprio.)

Ottimo. A me risultava che la forte polemica fosse partita nel tuo messaggio,
posso ovviamente sbagliare. Se abbassiamo i toni sono completamente d'accordo.
Se trovi parti del mio nuovo messaggio che ritieni inutilmente polemiche, ti chiedo
scusa in anticipo e segnalamele. 

> La tua teoria secondo cui tutto deve necessariamente essere così com'è
> si poteva (almeno, mi ero figurato che si potesse) motivare dal punto di
> vista dell'eleganza matematica _o_ dell'attinenza alla mentalità
> pythonesca: se tu dici che la matematica non c'entra niente, tirala pure
> via, altrimenti vai fino in fondo e facciamo le cose "bene", la
> precisione non è mai sgradevole.

Guarda, io sono una persona abbastanza pedante. Sono molto formale, a volte
pure troppo. Il motivo per cui vorrei lasciare perdere l'eleganza matematica e' che
spesso nel mondo pragmatico dei linguaggi di programmazione viene sacrificata
in molti punti e modi ben peggiori di questo. Il che vuole dire che appellarsi troppo
all'intuizione matematica non di rado porta fuori strada.

Di fatto sono pochissimi i linguaggi che non soffrono di questo problema, e a volte
sono parecchio scomodi proprio per questa ragione.

Io poi non sostengo che tutto debba essere come e'. Non ho parlato di "tutto".
Ti ho anche indicato un punto che trovo sgradevole (e che fortunatamente 
hanno fixato in Python 3). Posso aggiungere che mi piacerebbe che Python potesse
essere tail recursive (anche se so perche' non PUO' esserlo). Etc etc etc.

Riguardo al problema specifico, abbiamo sempre sta cosa qua. O sacrifichi l'aritmetica
mista (e lanci eccezioni), oppure tieni le cose come sono, con False che si comporta
come 0.

Se ho capito bene, tu vorresti 0 != da False *ma* avendo aritmetica mista. E questo
IMHO non porta da nessuna parte. 

> Stai scherzando?! Questo punto è stato chiarito 6 mail fa.
> _Evidentemente_
> if 0: print "ciao" -> ...
> if []: print "ciao" -> ...


No, non sto scherzando. Continui a chiedermelo. Se stessi scherzando
proverei con delle barzellette. Se scrivo su un gruppo tecnico, è probabile
che non stia scherzando.

Probabilmente non ti piace il Python idiomatico.
Utilizzare cose come

if len([]) == 0:

sono considerate *cattiva* pratica. Proporre di abbandonare la pratica
considerata "buona" di

if []: 

IMHO non è particolarmente sensato.

> Veramente ho concluso che _potrebbero_ benissimo esserlo, e che io lo
> troverei più intuitivo - a prescindere dall'abitudine, ovviamente.

Potrebbero essere qualunque cosa. La praticità della cosa rimarrebbe 
discutibile, tuttavia.

> Non ne vedo affatto la ragione. Se dopo tutte queste mail ti sfugge
> ancora la semantica che ho in mente, te la rispiego: il comportamento
> dei bool rimane _ovunque_ quello che è, tranne che 0 != False (e
> ovviamente ottieni risultati diversi se vai a vedere l'ereditarietà).

Mi sfugge perche' non mi sembrava scritto nero su bianco. Anzi, mi 
sembra che altaleni fra NON ammettere l'aritmetica mista e ammetterla
ma con 0 != da False.

> Come si ottiene? Levando l'ereditarietà e ridefinendo gli operatori
> necessari. Se c'è qualcosa di naif in questa idea di implementazione,
> sono tutt'orecchi (occhi), ma se la semantica di per sé non fosse valida
> forse gli "assurdi completi" che menzionavi varie mail fa sarebbero
> ormai venuti alla luce.

Quindi spiegami meglio, tu proponi questa semantica.

0 != False -> True
0 == False -> False

Ora dimmi cosa vuoi fare in questi casi:

10 * False  
10 + False 
0 < False
0 > False
0 < True
0 > True

Ovviamente, se tiri delle eccezioni, torniamo a quello che dico io.
La cosa che non capisco è: si continua a parlare di booleani che
si comportano come interi. Tu la sopra dici

"""il comportamento dei bool rimane _ovunque_ quello che è, tranne che 0 != False"""

Che va bene. Ergo posso assumere che tutte le operazioni di cui sopra
abbiano il consueto risultato. Tranne, immagino, cose come 0 < False, che ovviamente
cambiano. 

Per gli assurdi promessi, attendo le risposte alle domande di cui sopra.
Piu' precisa mi dai la semantica piu' mi e' facile scriverli. Altrimenti devo fare
molte assunzioni e per ogni scelta, essenzialmente, raddoppiare la dimostrazione.


> Immagina pure, io più chiaro non potevo essere.

Quindi 0.0 == 0 o no?
E 0L == 0 o no?[0]


----
[0] fintanto che ci sono i long, ma possiamo estendere il concetto
a razionali e complessi e altri tipi numerici eventualmente definiti in seguito.

> Per me puoi chiamare "numero" anche una mela, se ti fa comodo, riesci a
> infilarlo in un certo numero di bit e riesci ad infilarci qualche
> operazione aritmetica.

No, davvero, ripeto. Di quanti bit hai bisogno per considerarlo numero? 
Perchè le operazioni da numero il booleano le ha, e non in modo più
contraddittorio di quello che *oggi* siano fra interi e long. Deduco che
float e int, che sono bestie diversissime, sono numeri e devono essere 
trattati come numeri da quello che scrivi in seguito.

> In realtà ovviamente non è un problema di nomi. Il fatto è che non dirò
> "guarda, miracolo dell'informatica, la mela è un numero", ma "guarda,
> ...
> tutte le volte che voglio.

Ricordo qualcosa in proposito su un libro di Schopenhauer...
Tu hai parlato di mele, non io. Quello che vuoi fare con le mele è,
essenzialmente, affar tuo.

> Stai cercando di motivarmi con dettagli (non nel senso di "trascurabili
> per l'implementatore", ma nel senso di "auspicabilmente trascurabili per
> l'utilizzatore") la "comodità" e la "sensatezza" (e addirittura la
> necessarietà) di alcune regole degli operatori? In tutta onestà, non è
> quello di cui stavamo parlando.

No: tu hai tirato in ballo un grosso paragone con la matematica, io ti stavo
spiegando che spesso questo punto di vista è purtroppo fuorviante.
Non puoi aspettarti che una cosa funzioni in un certo modo in Python
perchè è così in matematica.

>> BTW, non tirare in ballo xor e compagnia, al momento non hanno nulla a che vedere.
> Nulla a che vedere con i booleani? 

Nulla a che vedere con il discorso, suvvia. Che trucchetto misero. :)
Non e' per essere polemico, ma mi sembrava chiaro che stavamo parlando
delle operazioni tipiche dell'aritmetica intera applicate ad interi e booleani
in modo mischiato.

> Di nuovo, ereditando dal C ci manca solo che ne perdiamo le comodità...

Ereditate dal C? Diciamo ereditate dalla CPU. Poco importa comunque.

> Appunto, ma se ogni volta che due oggetti *si comportano come* nel senso
> del duck typing avessi che risultano ==, impazzirei.

Purtroppo qui il problema e' molto "ideologico". Quando due oggetti "distinti"
sono legittimati ad avere un == che dice che sono uguali? Boh, dipende
dal dominio.

>> Oltretutto, quello che probabilmente ti sfugge è che se un animale è un cane,
>> un cane non è un intero.
> 
> Questo mi sfugge, sì. Forse manca la conclusione "ogni intero è
> mortale"?

Oh, pardon. Era se cane is-a animale, tipicamente non animale is-a cane.

>> Ergo se un booleano è un intero, un interno non è
>> un booleano.
> Ah, beh, che sia così nell'implementazione attuale non c'è dubbio,
> grazie.

No, accidenti. Tu continui a fare confusione su cosa sia l'ereditarietà.
E ripeto, non e' polemica. 

>> Considera anche questo... in Ruby false e nil sono gli unici valori veramente
>> falsi. Ovviamente Ruby funziona e tutto... ma viene spesso elencato fra le cose
>> contro-intuitive di Ruby. 
> 
> Di nuovo, trovo il duck typing fantastico.

Ti rendi conto che ti ho parlato di Ruby, che ha il comportamento da te richiesto,
e tu mi hai parlato del duck typing? Non è che nel mezzo ci siamo persi qualcosa?



Maggiori informazioni sulla lista Python