On Feb 13, 2010, at 2:58 PM, Pietro Battiston wrote:
> 2) argomentare con il fatto che se un programmatore, che è poi l'utente > del linguaggio, si trova ad utilizzare oggetti matematici - e.g. numeri > - dovranno comportarsi, per quanto possibile, come lui si aspetta. Sono d'accordo. Sotto ti faccio vedere come di fatto cose inaspettate salterebbero fuori comunque. > A volte l'1 pone dei vincoli necessari al 2; ciononostante del Python mi > piace che pone molta attenzione al 2 (vedi passare automaticamente da > int a long, perché di nuovo, quando come programmatore penso a "int" in > Python penso agli interi, non agli interi modulo INT_MAX). Come nota a margine, in C non hai sugli interi aritmetica modulare. Hai undefined behaviour quando sfori. L'aritmetica modulare la hai sugli unsigned (e quindi ocn UINT_MAX). Non che sia importante, solo una precisazione. >> sono considerate *cattiva* pratica. Proporre di abbandonare la pratica >> considerata "buona" di >> >> if []: >> >> IMHO non è particolarmente sensato. > > > Ma infatti non l'ho proposto, ed è la terza volta che cerco di > chiarirlo... Su questo punto quindi siamo d'accordo. In contesti di questo tipo 0 continuerebbe a valutare a False. Che poi, per dire, in effetti e' False che valuta a 0. Chi comanda e' il metodo __nonzero__, ma ok. >> Quindi spiegami meglio, tu proponi questa semantica. >> >> 0 != False -> True >> 0 == False -> False > > certo > >> >> Ora dimmi cosa vuoi fare in questi casi: >> >> 10 * False >> 10 + False > > il bool è convertito automaticamente in int ==> rispettivamente 0 e 10 Eh... poi ci troviamo con questo. Indichiamo con b un booleano, con n,m,... un intero e con a qualcosa che puo' essere indifferentemente un booleano o un intero. Il nostro obiettivo e' definire le operazioni su Bool U Int, rispettivamente l'insieme dei booleani e degli interi. Normalmente ci aspettiamo che: n + m - m == n siamo d'accordo? Lascio perdere le parentesi, poiche' in Python, grazie al "salto" a long abbiamo la proprieta' associativa. Supponiamo di estendere tale cosa agli "interi o booleani". Ricorda, vogliamo che i booleani si possano ancora usare al posto degli interi. False + m - m != False Infatti la prima parte viene convertita ad intera. False + m -> m ed m - m va a 0. Essenzialmente il problema e' che il nostro insieme Bool U Int si trova con due elementi neutri. L'algebra ci dice che se questi sono distinti non abbiamo piu' un gruppo, ovvero l'insieme (Bool U Int, +) non e' un gruppo. Questo e', in essenza, uno degli assurdi di cui parlavo. Per eliminare una cosa sgradevole matematicamente come avere False == 0, perdiamo alcune proprieta' fondamentali sulla struttura algebrica delle operazioni. Nota... per non dovere definire le operazioni su Bool U Int dobbiamo proibire l'aritmetica mista (come dicevo) oppure cambiare le proprita' di False e True, che non dovrebbero comportarsi come elementi cosi' particolari algebricamente come 0 ed 1. Il problema e' che non riusciamo a trovare nessun altro buon valore. Non possiamo metterli "in mezzo" fra due interi. Dobbiamo lasciare loro un valore tutto particolare e distinto da quello degli interi. Matematicamente si fa, voglio dire. A naso direi che ci imbatteremmo in qualche altro comportamento contro-intuitivo. Un'altra possibilita' e' intendere tutte le operazioni come operazioni su UxT dove U e' l'insieme di tutti i valori e T quello di tutti i tipi. Ma accidenti... IMHO viene proprio una cosa tosta. In questo senso mi sembra che la semplicita' di False e' praticamente un altro nome per 0 sia difficile da battere. >> 0 < False >> 0 > False >> 0 < True >> 0 > True >> > > Per come l'ho sostenuta sinora, semplicemente l'ordering tra tipi > diversi, ovvero int > bool in python 2.*, eccezione in python 3.* (se > non sbaglio). Poi preferisco la prima, ma questo è un altro discorso. Anche perche' se lanci eccezione, di fatto non e' vero che hai veramente "aritmetica" mista. Alcune operazioni "banali" che fai con gli interi (confronto) non puoi farle se uno dei due e' un booleano. > Sì. Non che veda niente di proibito in > > int < bool > definito come > int < int(bool) > > , ma non stavo pensavo a quello (che poi potrebbe essere pure più > comodo, non so). Sarebbe ovviamente l'unica scelta consistente con il "mischiare" interi e booleani. Quale e' il problema? A noi piace il principio del terzo escluso. Se due elementi non sono uno minore dell'altro (comunque li prendi), allora sono uguali. Eppure tu siccome vuoi che False "valuti" a 0 non puoi prenderlo ne minore ne maggiore di 0, ma di fatto non hai nemmeno 0 == False. Ovviamente, se per esempio prendi False > 0 poi ti saltano cose tipo 10 * False > 2 * False che a rigore dovresti avere. Questo perche' False continua a comportarsi come 0 e questo dovrebbe riflettersi nei confronti. > Ma ti rendi conto che per nessuno di questi valori in Python si è > ritenuto necessario introdurre un nuovo letterale (o una variabile)? Ti > sembra veramente un caso?! No, tutti questi valori hanno un nuovo letterale! I long li fai aggiungendo la L in fondo, i float con il punto. Per il parser sono tutti nuovi letterali. In Python 3 finalmente anche True e False sono letterali (o forse sono Keywords... boh). > > A me sembra un suggerimento, casomai ce ne fosse bisogno, del fatto che > il programmatore comune considera i bool prima come valori di verità e > solo in seguito come cose che possono "giocare" con/come i numeri. > > >> >> ---- >> [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? > > No, ho bisogno che sia un numero per considerarlo numero. Vorrei dire > "nella realtà", ma ovviamente mi farei ridere dietro: diciamo nella > mente del programmatore medio, quello per cui è stato deciso che > esistessero False e True, nonostante la loro attuale ridondanza rispetto > a 0 e 1. Esatto. Sono ridondanti. Semanticamente si considera piu' chiaro scrivere False che 0. Posso anche essere d'accordo. Poi per dire, per certe ottimizzazioni, in Python 2.x devi usare 1. Guarda il codice generato da while 1: ... e quello da while True: ... E no, non mi piace. Ma fintanto che si puo' ridefinire True... il giorno che mi voglio fare buttare fuori a calci lo faro' scrivendo codice tipo In [5]: i = 4 In [6]: while True: ...: if i < 0: True = False ...: else: i -= 1 > Non mi sembra ci sia _nessun_ altro caso, in qualsiasi tipo numerico in > python, in cui si ha > > b = a + a > type(b) != type(a) > a + a == b Comunque type(bool) == type(int). Che ovviamente discende dall'essere un bool un int. Comunque riprendo... poi stacco che mi sa che il pezzo i interessante del messaggio lo ho gia' scritto. Credo che la chiave sia accettare che == e' un uguaglianza *semantica* in Python, non un'uguaglianza sintattica. In un linguaggio ad oggetti, siamo abbastanza liberi di avere == che ci dice ok su oggetti di tipi diversi. Io poi confesso che questa parte di programmazione ad oggetti non la amo. Ma puo' avere un suo senso, dopotutto. > Poi in matematica puoi dire che le ha, ma in un modo tale che, ristrette > ai booleani, siano assolutamente stupide (e non per questo sbagliate > formalmente). Ossia _non_ le considero operazioni sui booleani. Non sono operazioni sui booleani. Come dicevo prima, un'operazione e' AxA -> A, qui invece siamo Bool x Bool -> Int *MA* sia A = Int U Bool, allora sono operazioni AxA -> A Allo stesso modo in cui in effetti le operazioni sugli interi, in Python, sconfinano nei long. Di fatto sono definite su (IntULong^2)->IntULong > OK, ammetto che come quoting può essere stato equivoco, ma non è un > "trucchetto misero"... io ho tirato in ballo xor e compagnia per fare > _notare_ che le operazioni classiche dei bool sono diverse da quelle > degli altri numeri. Si, ma per un *informatico* xor e compagnia sono assolutamente operazioni definite e definibili sugli interi, comunque. Proprio sfruttando la loro natura binaria a basso livello. Oggi ci si gioca meno, in univerista' non ci si lavora tantissimo. Forse le usano di piu' ad ingegneria e magari non vengono naturali agli altri, ma di per se sono tutte cose che ci aspettiamo da una qualunque ALU. Anzi.. conosco ALU che hanno xor e non hanno la moltiplicazione generica. Non scherzo. :) Roba vecchia, eh.Avevi moltiplicazione solo per due (visto che era uno shift) e la moltiplicazione generica era una procedura. La scrittura della quale e' lasciata per esercizio a chi voleva scriverci. Dalla mia memoria avevo estratto che forse la CPU del game boy aveva questa caratteristica, ma wikipedia non conferma e non smentisce, *ma* sembra piu' vicino a smentire. > Mi spiego meglio: ovviamente non stavo dicendo che, data A sottoclasse > di B, mi aspetterei > > is_instance(B(), A) --> True > > , ma che se A non introduce _niente_ di nuovo rispetto a B (e mi sembra > questo il caso per i booleani nei confronti degli int - a parte la > rappresentazione diversa, ovviamente), tanto vale abolirla... > > ... a meno che non siamo tanto affezionati alla rappresentazione proprio > perché per noi False e True _non_ sono 0 e 1. 1. se False e True fossero solo nomi per 0 e 1 sarei d'accordissimo. 2. la differenza "semantica" la vedi per esempio su __str__ che e' ridefinito per stampare False invece di 0 3. possibile ci siano altre cose che non mi vengono in mente, essenzialmente. Chiaramente se in C(99|++) i bool sono motivati anche dal consumo di spazio, questo non vale in Python, che io sappia. Spiace. > No, ti dicevo solo che per me in questo caso Ruby è OT perché sul fatto > che > if [] : print "ciao" -> ... > > è una bella cosa sono perfettamente d'accordo con te (e se ho capito > bene - ma ci avrò scritto 10 righe in vita mia - in Ruby non è così). Beh, Ruby propone un modello in cui interi e booleani non sono interoperabili. Come avevo scritto 0 + false da eccezione. Era uno dei modelli proposti. Io personalmente preferisco quello di Python, ma preferisco quello di Ruby a quello che proponi tu (ovvero aritmetica con booleani ma False != 0). Il perche' lo ho essenzialmente spiegato sopra. _______________________________________________ Python mailing list Python@lists.python.it http://lists.python.it/mailman/listinfo/python