PDA

View Full Version : Torvalds e C++


Pagine : 1 [2] 3

cdimauro
12-09-2007, 07:46
Alt: come disse Dante Alighieri: cerchiamo di non farla fuori dal vaso. O era Toni 'O Animale? Non ricordo.
E lo dici a me, che notoriamente soffro di scarsa memoria? :asd:
Anche ammesso che C++ abbia un modello, esso non è nè ben definito nè consistente. Indefinito per via del numero esorbitante di eccezioni al suo numero esorbitante di regole. E' come i cioccolatini di Forrest Gump: non sai mai quello che ti capita (ma puoi scommetterci che sa di m...).
Limitatamente alle sole classi, dove starebbero le regole esorbitanti contornate dalle altrettanto esorbitanti eccezioni?

Io trovo più semplice e naturale che una classe possa discendere da più classi, mentre vedo come un'eccezione i modelli basati sull'interfaccia (eredito da una sola classe, ma posso anche farlo da un certo numero di eccezioni, che però non sono classi vere e proprie ma "castrate" perché non posso avere variabili d'istanza e/o di classe e tutti i metodi sono virtuali).

Vorrei capire bene, se possibile, cos'è che ti fa andare di traverso il C++ (se vuoi andare oltre le classi mi sta anche bene, eh! Anzi, personalmente gradirei :D) facendo un paragone con Java e/o SmallTalk, con cui sei particolarmente ferrato.
Ed è assolutamente inconsistente. Tiene il piede in tre scarpe: oo, procedurale e funzionale. Nessuna della sua misura. Che sia orientato agli oggetti lo stabilì... Stroustrup. Lo scrisse all'ecoop: "what is object orientation". Capitò per caso che la definizione coincidesse esattamente con C++. Penso che ancora oggi sia l'unico a sostenerlo.
L'autoreferenzialità è una brutta malattia. :asd:
C'è un subset di C++ che è appetibile per l'orientamento agli oggetti. Ma è talmente sub che dovremmo parlare di --------C++.
OK, e questo si ricollega a quanto scritto sopra.

Il subset a cui ti riferisci sarebbe? Usare le classi di C++ come si farebbe con Java & co, quindi una sola classe discendente ed eventuali interfacce da implementare?
Dal punto di vista funzionale fa quello che fa C: siccome sono procedurale è tutto è un valore, anche le funzioni sono valori quindi posso usarle per le stesse operazioni elementari. Dunque sono funzionale. Non fa una grinza. Ne fa due.
Se il C++ è funzionale allora per LISP & compagnia dovremmo coniare un nuovo termine. :asd: (ovviamente non ce l'ho con te, eh!)
E' certamente procedurale ma, in tutta sincerità, un linguaggio procedurale te lo scrive anche mio nipote che ha tre anni. Per la faccenda dei nani sulle spalle dei giganti: nell'anno del signore 2007 sappiamo tutto quanto hanno scoperto i pionieri dei due secoli passati. Il minimo è che oggi si sappiano fare le cose di ieri.
Concordo. Ma penso la stessa cosa del C: non si sentiva certo il bisogno di un altro linguaggio procedurale, che non ha portato nessun contributo nella letteratura dei linguaggi di programmazione.
In conclusione, io penso che sia certamente preferibile l'abbozzo di orientamento agli oggetti rappresentato da C++ al perfetto proceduralese di C. Per una questione di espressività. Ma che, slegato da questo contesto, C++ sia da considerarsi come utile a qualcosa lo contesto con vigore.
Come ho detto, a me non piace proprio la sintassi del C++, ma riconosco che come linguaggio offre parecche funzionalità.
Che sia difficile definirlo funzionale devi scriverlo a Stroustrup. Per me non è manco OO, figurati.
Se t'avessi conosciuto una dozzina d'anni fa, gliel'avrei potuto chiedere quando l'ho conosciuto a New York. :p

cdimauro
12-09-2007, 07:51
Peggio. Mancano gli strumenti per costruirseli. Questo almeno nel C++ e' stato fatto correttamente, e probabilmente meglio che in altri linguaggi che l'hanno seguito. Con questi strumenti poco importa se le stringhe sono tipi primitivi, in quanto le puoi implentare in modo che funzionino come se lo fossero.
Esattamente. Ma se il C fosse il miglior linguaggio procedurale della storia, non avrebbe avuto alcuna difficoltà a implementarle in maniera semplice: sarebbe stato sufficiente l'overloading di operatori e funzioni per ottenerlo, senza per questo andare a scomodare gli oggetti.
Non fosse altro per una questione di omogeneita' : perche' confrontare un tipo in un modo e un altro in un altro ? Non e' solo questione estetica (che pur conta), ma anche un fatto pratico: nel momento in cui decido di astrarre e rendere la mia funzione piu' generica, come faccio ad implementare un algoritmo che funzioni bene per tutti i tipi se la stessa operazione ha nomi differenti ? Devo per forza passarla come argomento. Ora, se devo semplicemente ordinare una sequenza me la cavo anche con poco, ma quando i parametri diventano due, cinque, dieci, le cose si fanno alquanto fumose e forse si fa prima a reinventare la ruota :D (esercizio per il lettore: prendere l'esempio di programmazione generica fatta in C e preprocessore e implementare l'ordinamento l'ordinamento di una lista che funzioni con tipi predefiniti, stringhe "C" (char*) e future strutture dati :D).
Perfettamente d'accordo. Vedi anche sopra. :)
Neanche col C++ sono rose e fiori, sia chiaro, perche' appena si accenna un gerarchia oppure un qualcosa che non stia sullo stack si comincia a parlare di puntatori, che con gli operatori ridefiniti non vanno molto d'accordo :p.
Mumble mumble. Come mai?

cdimauro
12-09-2007, 07:57
D'altra parte bisogna ammettere che fare un linguaggio veramente multiparadigma e' decisamenet un'impresa. Incredibilmente, l'unico che conosco che faccia abbastanza bene un po' tutto e' uno dei piu' vecchi, ed e' Lisp (CLOS c'ha pure i multimetodi :mbe: )
Ehm... LISP l'ho studiato all'università (il mio carissimo prof. di linguaggi di programmazione ne era un fanatico sostenitore; d'altra parte era pure un matematico :D), più precisamente Scheme, ma onestamente che potesse far bene anche nella programmazione a oggetti non me lo ricordo (in quella procedurale non è che fosse il massimo, ma diciamo che era usabile :p).

cdimauro
12-09-2007, 08:02
appunto..
tu non hai i miei colleghi evidentemente :asd:
E tu non hai mai visto la piattaforma della mia azienda, che è realizzata per lo più in PHP... e non hai idea in che modo si intersechino le "classi" (lo metto tra virgolette perché sarebbe un'offesa chiamarle tali, visto che vengono usate per lo più per incapsulare dati e codice, visto che a questo schifoso linguaggio manca il concetto di modulo), e delle variabili globali che vengono settate in chissà quale sperduto script incluso chissà dove. :muro:

Fortunamente un po' alla volta alcune parti le sto riscrivendo in Python + Ice (simile a CORBA, ma decisamente più semplice e veloce da usare), ma è dura, anche perché c'è una forte tendenza a mantenere compatibilità con codice legacy. :(

PGI-Bis
12-09-2007, 10:09
Limitatamente alle sole classi le esorbitanti eccezioni sono almeno due. Il modificatore Friend è il primo. Anche trascurando per un attimo la sue norme di applicazione (nove gruppi ognuno dei quali contiene almeno due eccezioni, IsoIec14882, 11.4) esso eccepisce alle norme sull'astrazione. Un membro privato è tale per chiunque non sia amico di chi lo dichiari. E' privato, bene, si tratta di un dettaglio di implementazione. Beep, sbagliato: appartiene ad un contratto sovrapposto.

La seconda riguarda il collegamento statico predefinito. Tutta la parte di C++ relativa all'ereditarietà e, in particolare, a quell'aspetto dell'ereditarietà che è la specializzazione dei comportamenti, non si applica alle classi "normali": il tipo predefinito di collegamento in C++ è quello statico. Il collegamento dinamico in C++ è un'eccezione.

Poi abbiamo le dichiarazioni anticipate, i metodi inline, la trinità delle classi (struct, union e class sono tutte classi in C++, tutte con regole proprie). Il tutto condito dalla presenza del preprocessore, che rende il linguaggio un dialetto di sè stesso.

Ora, tutte le lingue hanno delle note incoerenti al loro interno. Alcune meno di altre. Ad esempio Smalltalk a me pare non averne. Ma la quantità in C++ è assolutamente soverchiante.

cdimauro
12-09-2007, 10:20
OK, finalmente è chiaro. :D

L'unico appunto te lo faccio sulle funzioni friend: è vero che il contratto viene "violato" ma, come dicevo tempo fa, in tanti linguaggii tramite l'uso dei cracker è possibile violare il contratto per gli attributi che sono stati definiti "protected", fancendoli diventare, di fatto, pubblici.

k0nt3
12-09-2007, 10:27
Postone unico e rispostone unico, saltando un po' di cose che si trascinano da tempo e sui è inutile dilungarci.

Al C mancano dei costrutti di più alto livello (stringhe, definizione di costanti, ecc.) che sono presenti in altri linguaggi procedurali (non necessariamente OOP, come affermavi) e che permettono di semplificare la vita a chi sviluppa.
Questo NON è un discorso soggettivo, ma oggettivo: se mancano, mancano, e c'è poco da fare.

Il C++ offre un modello di programmazione a oggetti che può non piacere (e qui è un discorso soggettivo; ad esempio a me piace l'ereditarietà multipla, ma NON la sintassi del C++), ma è molto espressivo / versatile (copre parecchi casi: vedi ad esempio quello delle classi basi virtuali di cui ho postato un link), nonché ben definita e consistente.
Inoltre non impedisce a nessuno di usare le classi esattamente come si farebbe con le interfacce; infatti la programmazione tramite interfacce è un caso particolare dell'ereditarietà multipla (e questo è banale da capire: le interfacce in C++ altro non sarebbero che classi dotate esclusivamente di metodi virtuali e astratti).
Sulle classi base virtuali è bene precisare che rappresentano una precisa scelta dello sviluppatore; in questo la filosofia del C++ è ben chiara: è il programmatore che sa quello che fa, e il compilatore non prende iniziative (come potrebbe fare il compilatore D), anche perché potrebbe NON essere desiderabile l'iniziativa.
Al C++, come a tanti linguaggi, mancano moduli e/o package; personalmente è un GROSSA mancanza, e infatti bisogna ricorrere al preprocessore (indispensabile anche in ottica della compatibilità col passato). In questo caso è da biasimare tanto quanto il C.

Quanto alle proprietà al posto dei metodi, sono sicure nella misura in cui come sviluppatore le uso in maniera appropriata, quindi con dei metodi getter e setter; le proprietà, infatti, servono a controllare l'accesso alle risorse, ma in maniera più semplice e leggibile.
Esempio (in Delphi):
TTavolo = class(TRunTimeDrawable)
private
FIDPiano: Integer;
FPosti: Integer;
procedure SetPosti(const Value: Integer);
public
property IDPiano: Integer read FIDPiano;
property Posti: Integer read FPosti write SetPosti;
end;

procedure TTavolo.SetPosti(const Value: Integer);
begin
if FPosti <> Value then begin
FPosti := Value;
SaveDatas;
end;
end;
In questo caso l'intento è chiaro:
- IDPiano è una proprietà accessibile a sola lettura; poiché a sola lettura mi posso permettere il lusso di farla leggere direttamente senza l'ausilio di un metodo getter;
- Posti è una proprietà accessibile anche in scrittura, ma in maniera controllata perché l'accesso è regolato sempre da un metodo setter (che si occupa, oltre a memorizzare il nuovo valore, a far scattare il metodo SaveDatas).

Semplice, lineare e di più facile lettura, perché anziché ricorrere a

Istanza.SetPosti(NuovoValore);

è sufficiente una

Istanza.Posti := NuovoValore;

;)

E' tutto.
:doh: negli ultimi commenti ti sei dimenticato il trattato di quotatura unica :O

è vero che al C mancano i costrutti di alto livello, ma è anche vero che se li vuoi puoi usare altri linguaggi (anche precedenti al C). non vedo perchè il C avrebbe dovuto essere una copia di qualcos'altro. in fondo se è diventato così usato è proprio perchè non aveva questi costrutti permettendo una programmazione più efficiente (oggi invece le cose sono un pò diverse).
comunque sia devo dare ragione a Torvalds quando dice che tra C e C++ cambia soprattutto la mentalità e nel caso di GIT la mentalità giusta è quella del C perchè non bisogna astrarre un bel niente

finalmente ho avuto il tempo di leggere il link sulle classi base virtuali... e dirò che sono concetti inutili al fine di programmare a oggetti. la programmazione OO nasce per dimenticarsi della struttura della macchina e tu mi vieni a dire che devi usare virtual perchè altrimenti esistono due istanze della superclasse nell'oggetto? :confused: (e in C++ esempi di questo genere si sprecano)

quando dicevo che il compilatore D ci pensa da solo intendevo solamente nel caso in cui sa qual'è la cosa migliore da fare. sicuramente permettere due istanze di Person nello stesso oggetto non è una buona scelta. detto questo il D permette l'ereditarietà multipla solo attraverso le interfaccie, ma consente anche di non dover riscrivere codice inutilmente grazie ai mixins (roba che ancora mi devo studiare :p ). quando si dice la botte piena e la moglie ubriaca

il fatto dei package/moduli non è solo questione di evitare l'uso del preprocessore, ma è proprio un concetto utile alla programmazione ad oggetti. il C# usa i namespace, e quindi non aggiunge niente al C++ da questo punto di vista.

per quanto riguarda le proprietà non vedo nessun vantaggio tra usare:
Istanza.Posti := NuovoValore;
al posto di:
Istanza.SetPosti(NuovoValore);

anzi vedo soltanto uno svantaggio per il primo caso.. più che altro legato alla leggibilità del codice. infatti se uno legge quella riga di codice ha l'impressione che si tratti di un semplice assegnamento di variabile, mentre invece entra in gioco (implicitamente) una funzione. il problema è che uno tutte volte si deve andare a leggere la dichiarazione della proprietà per vedere se e come era stato definito l'assegnamento :fagiano: pure quando non è stato definito
comunque è già più pulita questa sintassi di delphi rispetto al C# dove bisogna implementare il metodo contestualmente alla dichiarazione della variabile

k0nt3
12-09-2007, 10:31
Concordo. Ma penso la stessa cosa del C: non si sentiva certo il bisogno di un altro linguaggio procedurale, che non ha portato nessun contributo nella letteratura dei linguaggi di programmazione.

dire che il C non ha apportato nessun contributo significa fare finta di non sapere che ha influenzato buona parte dei linguaggi successivi :read:

k0nt3
12-09-2007, 10:34
OK, finalmente è chiaro. :D

L'unico appunto te lo faccio sulle funzioni friend: è vero che il contratto viene "violato" ma, come dicevo tempo fa, in tanti linguaggii tramite l'uso dei cracker è possibile violare il contratto per gli attributi che sono stati definiti "protected", fancendoli diventare, di fatto, pubblici.
non è un problema del linguaggio però

marco.r
12-09-2007, 11:33
Ehm... LISP l'ho studiato all'università (il mio carissimo prof. di linguaggi di programmazione ne era un fanatico sostenitore; d'altra parte era pure un matematico :D), più precisamente Scheme, ma onestamente che potesse far bene anche nella programmazione a oggetti non me lo ricordo (in quella procedurale non è che fosse il massimo, ma diciamo che era usabile :p).
Pardon, in realta' intendevo un dialetto specifico, il Common Lisp. Scheme è orientato piu' verso la programmazione funzionale. CL invece si mangia indifferentemente codice funzionale (mapcar e compagnia, funzioni come valori etc.), programmazione oop (defclass, defmethod etc.) e procedurale nel senso piu'puro del termine (goto compreso :eek: :D). La cosa bellina è che molte funzionalità possono essere implementate nel linguaggio stesso sotto forma di macro, anche se queste non sono della stessa eleganza di quelle offerte da scheme (define-syntax e' una vera e propria bellezza :p)

marco.r
12-09-2007, 11:35
dire che il C non ha apportato nessun contributo significa fare finta di non sapere che ha influenzato buona parte dei linguaggi successivi :read:
Resta da stabilire se ciò sia stato un bene o un male... :fagiano:

k0nt3
12-09-2007, 11:40
(goto compreso :eek: :D)
vade retro satana :asd:

Resta da stabilire se ciò sia stato un bene o un male...
parlo soprattutto di C++, java, C#, D e javascript.. quindi della sintassi più che altro (ma per alcuni non solo)

PGI-Bis
12-09-2007, 12:21
La questione protected è simile al friend. D'altronde il fatto che una lingua abbia delle magagne non significa che tutte le altre ne siano esenti.

Se prendiamo ad esempio il linguaggio di programmazione Java, il modificatore protected dice che il membro è tranquillamente pubblicabile da ogni sottotipo. La cosa è oltremodo problematica: è come un contratto a termine, scaduto il quale tutto è possibile. Da più garanzie la restrizione a livello di package. L'ideale sarebbe comunque non avere alcun modificatore: campi privati e metodi pubblici. Vale perchè il metodo privato altro non sarebbe che il metodo pubblico di un oggetto privato la cui definizione partecipa alla definizione di chi l'abbia per campo. E' facile da ricordare perchè esisterebbe una sola regola mai eccepita.

RaouL_BennetH
12-09-2007, 12:22
un pò OT ma si riferisce alle checked exception di cui avete fatto menzione prima in C#, guardate che bello quando due grandi dialogano tra di loro in maniera civile pur avendo idee differenti:

"Remaining Neutral on Checked Exceptions

Bruce Eckel: C# doesn't have checked exceptions. How did you decide whether or not to put checked exceptions into C#?

Anders Hejlsberg: I see two big issues with checked exceptions: scalability and versionability. I know you've written some about checked exceptions too, and you tend to agree with our line of thinking.

Bruce Eckel: I used to think that checked exceptions were really great.

Anders Hejlsberg: Exactly. Frankly, they look really great up front, and there's nothing wrong with the idea. I completely agree that checked exceptions are a wonderful feature. It's just that particular implementations can be problematic. By implementing checked exceptions the way it's done in Java, for example, I think you just take one set of problems and trade them for another set of problems. In the end it's not clear to me that you actually make life any easier. You just make it different.

Bruce Eckel: Was there a lot of disagreement in the C# design team about checked excpetions?

Anders Hejlsberg: No, I think there was fairly broad agreement in our design group.

C# is basically silent on the checked exceptions issue. Once a better solution is known—and trust me we continue to think about it—we can go back and actually put something in place. I'm a strong believer that if you don't have anything right to say, or anything that moves the art forward, then you'd better just be completely silent and neutral, as opposed to trying to lay out a framework.

If you ask beginning programmers to write a calendar control, they often think to themselves, "Oh, I'm going to write the world's best calendar control! It's going to be polymorphic with respect to the kind of calendar. It will have displayers, and mungers, and this, that, and the other." They need to ship a calendar application in two months. They put all this infrastructure into place in the control, and then spend two days writing a crappy calendar application on top of it. They'll think, "In the next version of the application, I'm going to do so much more."

Once they start thinking about how they're actually going to implement all of these other concretizations of their abstract design, however, it turns out that their design is completely wrong. And now they've painted themself into a corner, and they have to throw the whole thing out. I have seen that over and over. I'm a strong believer in being minimalistic. Unless you actually are going to solve the general problem, don't try and put in place a framework for solving a specific one, because you don't know what that framework should look like.

Bruce Eckel: The Extreme Programmers say, "Do the simplest thing that could possibly work."

Anders Hejlsberg: Yeah, well, Einstein said that, "Do the simplest thing possible, but no simpler." The concern I have about checked exceptions is the handcuffs they put on programmers. You see programmers picking up new APIs that have all these throws clauses, and then you see how convoluted their code gets, and you realize the checked exceptions aren't helping them any. It is sort of these dictatorial API designers telling you how to do your exception handling. They should not be doing that. "

/OT

PGI-Bis
12-09-2007, 12:32
Eckel è uno che non ha mai dato segno di voler capire le eccezioni, specialmente quelle controllate. Basta vedere il suo thinking in java. Che ha un che di Java ma non troppo di thinking.

Esiste una precisa teoria dietro il meccanismo delle eccezioni che inizia dal concetto di scopo di un blocco di istruzioni e indaga sulle ragioni del mancato raggiungimento di tale scopo. Java ne fornisce un'intepretazione esemplare e, francamente, chi non lo veda dovrebbe farsi più di una domanda.

cdimauro
12-09-2007, 13:24
:doh: negli ultimi commenti ti sei dimenticato il trattato di quotatura unica :O

è vero che al C mancano i costrutti di alto livello, ma è anche vero che se li vuoi puoi usare altri linguaggi (anche precedenti al C). non vedo perchè il C avrebbe dovuto essere una copia di qualcos'altro. in fondo se è diventato così usato è proprio perchè non aveva questi costrutti permettendo una programmazione più efficiente (oggi invece le cose sono un pò diverse).
comunque sia devo dare ragione a Torvalds quando dice che tra C e C++ cambia soprattutto la mentalità e nel caso di GIT la mentalità giusta è quella del C perchè non bisogna astrarre un bel niente

finalmente ho avuto il tempo di leggere il link sulle classi base virtuali... e dirò che sono concetti inutili al fine di programmare a oggetti. la programmazione OO nasce per dimenticarsi della struttura della macchina e tu mi vieni a dire che devi usare virtual perchè altrimenti esistono due istanze della superclasse nell'oggetto? :confused: (e in C++ esempi di questo genere si sprecano)

quando dicevo che il compilatore D ci pensa da solo intendevo solamente nel caso in cui sa qual'è la cosa migliore da fare. sicuramente permettere due istanze di Person nello stesso oggetto non è una buona scelta. detto questo il D permette l'ereditarietà multipla solo attraverso le interfaccie, ma consente anche di non dover riscrivere codice inutilmente grazie ai mixins (roba che ancora mi devo studiare :p ). quando si dice la botte piena e la moglie ubriaca

il fatto dei package/moduli non è solo questione di evitare l'uso del preprocessore, ma è proprio un concetto utile alla programmazione ad oggetti. il C# usa i namespace, e quindi non aggiunge niente al C++ da questo punto di vista.

per quanto riguarda le proprietà non vedo nessun vantaggio tra usare:
Istanza.Posti := NuovoValore;
al posto di:
Istanza.SetPosti(NuovoValore);

anzi vedo soltanto uno svantaggio per il primo caso.. più che altro legato alla leggibilità del codice. infatti se uno legge quella riga di codice ha l'impressione che si tratti di un semplice assegnamento di variabile, mentre invece entra in gioco (implicitamente) una funzione. il problema è che uno tutte volte si deve andare a leggere la dichiarazione della proprietà per vedere se e come era stato definito l'assegnamento :fagiano: pure quando non è stato definito
comunque è già più pulita questa sintassi di delphi rispetto al C# dove bisogna implementare il metodo contestualmente alla dichiarazione della variabile
E' inutile: quotare è più forte di me. :p Ci riprovo col megaquotone. :D

Togliere costrutti a un linguaggio non lo rende automaticamente più efficiente, e il C non fa eccezione. Non vedo come operator e function overloading, tanto per tornare a fare lo stesso esempio, possano inficiare la velocità di esecuzione del codice prodotto. ;)

Su GIT non mi pronuncio perché, come ho detto, non conosco il progetto né tanto meno ho messo mano ai sorgenti, ma nella mia esperienza di progetti che non abbiano avuto bisogno di costrutti di più alto livello per codificare la soluzione in maniera più semplice e/o manutenibile ne conosco ben pochi, a maggior ragione se si tratta di roba da diverse migliaia di righe di codice. ;)

Per quanto riguarda il C++, le classi base virtuali non c'entrano nulla con la struttura della macchina: se esistono è per motivi di efficienza relativamente allo spazio occupato dai dati, e nulla di più.

Su D non mi pronuncio, perché lo conosco poco.

Moduli et similia come ho detto prima sono molti utili, e ribadisco che il preprocessore mi sta pure molto antipatico. :p

Infine sulle proprietà, a mio avviso la leggibilità è maggiore perché ti permette di concentrarti sull'unica cosa che veramente è importante: il dato.
Non me ne può fregar di meno se il dato che leggo da una proprietà proviene da una variabile d'istanza o è calcolato da un metodo: m'importa soltanto che mi venga restituito un valore di un certo tipo e di cui conosco il significato.
Il dettaglio puramente implementativo non è importante. Per lo meno non per chi deve USARE una certa classe.
La sintassi di C# in merito la trovo orribile: MOLTO, ma MOLTO più elegante e autoesplicativa è quella di Delphi. As usual. :p
non è un problema del linguaggio però
Non prendiamoci in giro: è il linguaggio che lo permette.
dire che il C non ha apportato nessun contributo significa fare finta di non sapere che ha influenzato buona parte dei linguaggi successivi :read:
parlo soprattutto di C++, java, C#, D e javascript.. quindi della sintassi più che altro (ma per alcuni non solo)
Io di un linguaggio preferisco analizzare innazitutto le FUNZIONALITA' che mette a disposizione, e da questo punto di vista, ripeto, il C non ha portato NULLA di nuovo.

E' vero che ha influenzato altri linguaggi per la sintassi, ma la trovo BEN POCA COSA. E poi su queste cose, come ben sai, le opinioni sono decisamente soggettive (a me fanno schifo i linguaggi con sintassi C-like, e non digerisco proprio la presenza di alcuni operatori tipici del C in Python). ;)

cdimauro
12-09-2007, 13:26
Pardon, in realta' intendevo un dialetto specifico, il Common Lisp. Scheme è orientato piu' verso la programmazione funzionale. CL invece si mangia indifferentemente codice funzionale (mapcar e compagnia, funzioni come valori etc.), programmazione oop (defclass, defmethod etc.) e procedurale nel senso piu'puro del termine (goto compreso :eek: :D).
:eek: GLOM. Era da eoni che non leggevo la parola "goto". :p
La cosa bellina è che molte funzionalità possono essere implementate nel linguaggio stesso sotto forma di macro, anche se queste non sono della stessa eleganza di quelle offerte da scheme (define-syntax e' una vera e propria bellezza :p)
Sembra interessante, ma di LISP & affini non mi piace l'eccessivo uso di parentesi che si deve fare: a volte mi saltano gli occhi soltanto a guardare i sorgenti. :read:

cdimauro
12-09-2007, 13:29
La questione protected è simile al friend. D'altronde il fatto che una lingua abbia delle magagne non significa che tutte le altre ne siano esenti.

Se prendiamo ad esempio il linguaggio di programmazione Java, il modificatore protected dice che il membro è tranquillamente pubblicabile da ogni sottotipo. La cosa è oltremodo problematica: è come un contratto a termine, scaduto il quale tutto è possibile. Da più garanzie la restrizione a livello di package. L'ideale sarebbe comunque non avere alcun modificatore: campi privati e metodi pubblici. Vale perchè il metodo privato altro non sarebbe che il metodo pubblico di un oggetto privato la cui definizione partecipa alla definizione di chi l'abbia per campo. E' facile da ricordare perchè esisterebbe una sola regola mai eccepita.
Io mi chiedo se sia veramente necessario "blindare" degli attributi e/o metodi: non poche volte mi sono ritrovato con l'impossibilità di poter estendere una classe per aggiungere semplicemente dei dettagli (che quindi non ne stravolgevano il significato).

P.S. Sulle checked exception non mi pronuncio perché non ho mai avuto l'occasione per approfondire questo particolare aspetto di Java.

PGI-Bis
12-09-2007, 15:09
Come sai io rifiuto il concetto di bene o male applicato alla programmazione. La pubblicazione, sia essa pubblicazione di un attributo piuttosto che di una funzione, ha delle conseguenze strutturali. Rendere una cosa pubblica significa stabilire che possono esistere altre parti del programma che dipendono dall'esistenza di quella cosa. Autorizza la creazione di quella dipendenza di definizione che comporta la perdita della qualifica di oggetto da parte della definizione dipendente.

Parlammo a suo tempo della direzionalità di questa dipendenza. Se A è una definizione dipendente da B allora B ed A+B sono oggetti.

Che B sia oggetto significa che la sua definizione non è alterabile dall'esterno. E' una sorta di atomo immutabile. A non è oggetto perchè subisce il riflesso di una eventuale mutazione della definizione di B.

Ebbene qui sta il punto del tanto citato problema della "pubblicazione dei campi". Che non è, badiamo bene, un problema esclusivo dei campi: si applica anche ai mutatori, cioè i metodi che permettono di intervenire sul valore di uno stato dell'oggetto.

Consentire l'alterazione di uno stato tramite pubblicazione del campo o di un suo mutatore significa aprire le porte ad un'alterazione della definizione dell'oggetto che possieda quel campo.

Vale a dire, la partita non si gioca sul piano del campo o del metodo, ma su quello della lettura e scrittura. La differenza tra campo e metodo sta nel fatto che il campo (a meno che non sia un riferimento terminale, cioè non riassegnabile) è riscrivibile.

Poichè ai fini dell'orientamento agli oggetti il campo vale in quanto definizione e poichè la presenza di questa definizione all'interno di un'altra testimonia l'esistenza di un certo oggetto piuttosto che un altro, l'alterabilità di quella parte di definizione comporta una trasformazione della struttura del sistema: prima c'era un certo oggetto e adesso ce n'è altro.

La cosa è di particolare evidenza nei linguaggi amorfi. Supponiamo che io abbia la seguente definizione:

object Ciccio {
public var campoPippo;

public def metodo() {
campoPippo.getValue() + 10;
}
}

Pseudo-lingua. Una mutazione di campoPippo può comportare una mutazione della dipendenza tra Ciccio e Pippo in dipendenza tra Ciccio e Qualcos'altro: è sufficiente che campoPippo diventi qualcosa che non abbia "getValue()". Detto in termini OO ciò significa che il mio sistema è costuito da un numero indeterminato di oggetti più un oggetto che dipende da ognuno di essi.

Nei sistemi polimorfi il problema sussiste o non sussiste secondo l'estensione del concetto di definizione che vogliamo abbracciare.

Personalmente sono portato a considerare definizione l'insieme delle dichiarazioni che costituiscono una definizione, a prescindere dal fatto che esse siano o no pubbliche. Vale a dire che la possibilità di sostituire Pippo in Ciccio comporta una mutazione costitutiva dell'oggetto a prescindere dal fatto che il sostituto rispetti il contratto di Pippo.

Non è l'unica strada. Il principio di sostituibilità di Liskow ci dice che è possibile limitare il concetto di definizione ad una dichiarazione pubblica vincolata da un insieme di precondizioni e postcondizioni. Se così fosse allora la pubblicazione di un campo o di un mutatore non comporterebbe un'alterazione dell'oggetto. C'è qualcosa che non mi torna in questo ma una sensazione che non ho mai approfondito.

cdimauro
12-09-2007, 15:23
Non è strano: le precondizioni e le postcondizioni rappresentano la formalizzazione del contratto che è stato "stipulato" fra chi ha creato la classe e chi la deve usare. Eiffel è l'esempio più noto di linguaggio di programmazione "by contract".

Detto ciò, alla fine la questione della pubblicazione o meno di attributi dipende dalla bontà delle scelte di chi ha progettato le classi (ed è la fonte delle mie incazzature :D).

cionci
12-09-2007, 15:26
PGI....ma scrivi questo libro dai. Sei troppo :sbavvv:
Ovviamente magari metti una bella bibliografia...altrimenti non ci capisco niente :sofico:

PGI-Bis
12-09-2007, 15:28
Lo ridico in una frase. Consentire la scrittura di un attributo rende il programma una gelatina, a prescindere dal fatto che questo sia permesso tramite un setter piuttostochè attraverso un campo. Certo così sembra un po' arbitrario :D.

cdimauro
12-09-2007, 15:41
Lo ridico in una frase. Consentire la scrittura di un attributo rende il programma una gelatina, a prescindere dal fatto che questo sia permesso tramite un setter piuttostochè attraverso un campo. Certo così sembra un po' arbitrario :D.
Decisamente, anche perché un modo per poter conservare delle informazioni vorrei riuscire a trovarlo. :p

PGI-Bis
12-09-2007, 16:06
Arbitrario è il concetto riassunto in un frase. Non lo è nella sua esposizione completa. Il mitologico "dato" della programmazione strutturata nell'orientamento agli oggetti altro non è che una definizione immutabile. Naturalmente uno può scegliere di usare lo strumento che preferisce. Nulla può impedire che io scriva un megastrutturone in Java. Ciò che è importante è la consapevolezza delle conseguenze di quella scelta.

thebol
12-09-2007, 18:16
Arbitrario è il concetto riassunto in un frase. Non lo è nella sua esposizione completa. Il mitologico "dato" della programmazione strutturata nell'orientamento agli oggetti altro non è che una definizione immutabile. Naturalmente uno può scegliere di usare lo strumento che preferisce. Nulla può impedire che io scriva un megastrutturone in Java. Ciò che è importante è la consapevolezza delle conseguenze di quella scelta.
tutto immutabile?
sarebbe un vantaggio anche dal punto di vista della programmazione concorrente...

l'unico grosso inconveniente è se la creazione dell'oggetto è di per sè molto costosa...

PGI-Bis
12-09-2007, 19:19
E' vero. Tuttavia io tendo ad invitare sempre a non pensare ai "massimi sistemi". La faccenda è molto più pratica, più terra terra di quanto possa sembrare. Molti dei tipi predefiniti contenuti nei linguaggi OO sono immutabili o in via sintattica o per consuetudine. L'immutabilità delle definizioni taglia le teste di molti tori perchè se è vero che l'intrecciarsi di definizioni che compongono un oggetto ci dice quali parti del sistema possono mutare e quali sono i riflessi di tali mutazioni, la precondizione di immutabilità riduce di molto la complessità dell'analisi.

Pensiamo ad esempio alle stringhe Java (o ai tipi numerici in qualsiasi lingua). La presenza di una stringa nella definizione di un'ipotetica classe Pippo ci dice che quella classe è parte di un oggetto la cui definizione abbraccia sia il contenuto di quella classe che il contenuto della classe String.

La naturale conseguenza di questo fatto è che una mutazione nella definizione di String è potenzialmente lesiva dell'integrità della definizione di un altro oggetto.

Assumendo l'immutabilità della definizione di String la sua partecipazione alla definizione di Pippo diventa "dinamicamente irrilevante". Se non può mutare è giocoforza che non sussista un problema di mutazione riflessa.

^TiGeRShArK^
12-09-2007, 19:37
E' vero. Tuttavia io tendo ad invitare sempre a non pensare ai "massimi sistemi". La faccenda è molto più pratica, più terra terra di quanto possa sembrare. Molti dei tipi predefiniti contenuti nei linguaggi OO sono immutabili o in via sintattica o per consuetudine. L'immutabilità delle definizioni taglia le teste di molti tori perchè se è vero che l'intrecciarsi di definizioni che compongono un oggetto ci dice quali parti del sistema possono mutare e quali sono i riflessi di tali mutazioni, la precondizione di immutabilità riduce di molto la complessità dell'analisi.

Pensiamo ad esempio alle stringhe Java (o ai tipi numerici in qualsiasi lingua). La presenza di una stringa nella definizione di un'ipotetica classe Pippo ci dice che quella classe è parte di un oggetto la cui definizione abbraccia sia il contenuto di quella classe che il contenuto della classe String.

La naturale conseguenza di questo fatto è che una mutazione nella definizione di String è potenzialmente lesiva dell'integrità della definizione di un altro oggetto.

Assumendo l'immutabilità della definizione di String la sua partecipazione alla definizione di Pippo diventa "dinamicamente irrilevante". Se non può mutare è giocoforza che non sussista un problema di mutazione riflessa.
ecco..
questo concetto dell'immutabilità degli oggetti mi sfugge :mbe:
metti caso ke hai una macchina con i cerchi di serie...
gli monti i cerchi in lega..
ebbene l'oggetto macchina è mutato perchè non è + collegato agli oggetti cerchi di serie ma è collegato agli oggetti cerchi in lega...
Ma la macchina è sempre quella...
non è ke per cambiare i cerchi io butto la mia macchina e ne compro una uguale con i cerchi che mi piacciono di + :fagiano:
Per come la vedo nella programmazione OO la non varianza degli oggetti porta + danni ke benefici :mbe:

P.S. mi devi passare la ricetta della zuppa :O

:asd:

PGI-Bis
12-09-2007, 20:11
Credo che anche questo punto sia stato esaminato nel tempo che fu. Ma se interessa non sia mai che io mi tiri indietro: c'è da blaterare, ecchime.

Il problema è nella frase: "la macchina è sempre quella". Ti faccio la versione breve.

Se dico che la definizione di macchina non dipende dalla definizione di cerchio in lega, pur essendo quest'ultima parte della prima, allora stabilisco implicitamente che esistono due categorie di caratteristiche: le caratteristiche essenziali e le caratteristiche non essenziali. E questo è esattamente il precipizio in cui è caduta la teoria classica (quella delle gerarchie linneiane). Non è possibile dare una definizione di essenzialità che prescinda dall'oggetto esaminato.

Ciò che invece si può dire con logica certezza è che se due oggetti sono distinti allora essi differiscono per almeno un attributo. Se così non fosse essi cesserebbero di essere "due" oggetti: non avrei modo di distinguerli.

Io so che se una macchina è diversa da un'altra è perchè c'è almeno una caratteristica che le distingue. Ciò che non so è quale o quali tra tutte le caratteristiche possedute dalla macchina siano quelle propriamente definenti. Non lo so perchè non possiedo un criterio di determinazione assoluto.

Capita allora che la sostituzione del cerchio di serie con quello in lega sia fatta a rischio di pregiudizio per l'integrità della definizione di macchina.

Non potendo definire un criterio di essenzialità ma trovandoci comunque di fronte alla necessità logica di motivare la distinzione tra gli oggetti noi non possiamo che abbracciare l'ipotesi che ogni caratteristica in quanto tale sia definente.

^TiGeRShArK^
12-09-2007, 20:56
CUT
si..
ma guardala un attimino in modo + pratico..
se tu dovessi scegliere se comprare una macchina a cui cambiare tutti i pezzi e comprare una macchina ke non puoi assolutamente toccare e dovresti ricomprare solo per cambiare un pezzo cosa sceglieresti? :mbe:

PGI-Bis
12-09-2007, 21:17
Sceglierò di creare l'una o l'altra a seconda che il sistema di riferimento contenga l'una o l'altra. O entrambe.

Mi sfugge tuttavia il punto della metafora: perchè non posso definire una macchina i cui pezzi cambiano?

k0nt3
12-09-2007, 21:21
riguardo al principio di liskov è molto semplice comunque, se questa relazione tra i tipi è rispettata:
"A subtype must require no more and promise no less than its supertype"
allora siamo sicuri che l'oggetto non subisce una trasformazione

purtroppo sarebbe utile un supporto del linguaggio stesso riguardo a questo argomento e la programmazione by contract va in questo senso

in D succede questo

If a function in a derived class overrides a function in its super class, then only one of the in contracts of the function and its base functions must be satisfied. Overriding functions then becomes a process of loosening the in contracts.
A function without an in contract means that any values of the function parameters are allowed. This implies that if any function in an inheritance hierarchy has no in contract, then in contracts on functions overriding it have no useful effect.
Conversely, all of the out contracts needs to be satisfied, so overriding functions becomes a processes of tightening the out contracts.
e per quanto riguarda le invarianti di classe vengono ereditate dal sottotipo

k0nt3
12-09-2007, 21:32
spiego meglio in che senso non subisce una trasformazione...
se io ho una classe A e B è un suo sottotipo allora dovrei poter usare un'istanza di B anche pensando che si tratti di un'istanza di A e questa si dovrebbe comportare esattamente come qualsiasi istanza di A (pur essendo un B).
questo si ottiene con la regola che ho postato sopra

^TiGeRShArK^
12-09-2007, 21:36
Sceglierò di creare l'una o l'altra a seconda che il sistema di riferimento contenga l'una o l'altra. O entrambe.

Mi sfugge tuttavia il punto della metafora: perchè non posso definire una macchina i cui pezzi cambiano?
:mbe:
xkè stai dicendo ke gli attributi sono immutabili... o no? :fagiano:
se gli attributi sono immutabili come fai a cambiare il valore di un attributo e quindi a modificare un pezzo della macchina? :mbe:

^TiGeRShArK^
12-09-2007, 21:38
spiego meglio in che senso non subisce una trasformazione...
se io ho una classe A e B è un suo sottotipo allora dovrei poter usare un'istanza di B anche pensando che si tratti di un'istanza di A e questa si dovrebbe comportare esattamente come qualsiasi istanza di A (pur essendo un B).
questo si ottiene con la regola che ho postato sopra
ehmm..
ma io non mi stavo riferendo a cambiamenti di funzionalità ke sono ottenibili con l'overriding..
stavo semplicemente parlando della variazione degli attributi...
il ke mi farebbe diventare la programmazione ad oggetti simile, almeno per quest'aspetto, a quella funzionale...
o non ho capito una mazza del vostro discorso? :fagiano:

k0nt3
12-09-2007, 21:40
mmm adesso che ci penso non sono sicuro di aver capito :p

PGI-Bis
12-09-2007, 21:52
Che ore sono. Giovedì.

L'immutabilità della definizione di un attributo riscrivibile pubblicato direttamente o indirettamente tramite setter riduce la complessità delle mutazioni riflesse.

PGI-Bis
12-09-2007, 21:54
Che non vuol dire che gli attributi non possono essere cambiati. Significa invece che se io uso come attributo di una macchina una definizione di cerchione che può diventare cerchio in lega o cerchio di serie allora la mia definizione di macchina include sia la definizione di cerchio in lega che quella di cerchio di serie.

^TiGeRShArK^
12-09-2007, 21:55
Che ore sono. Giovedì.

L'immutabilità della definizione di un attributo riscrivibile pubblicato direttamente o indirettamente tramite setter riduce la complessità delle mutazioni riflesse.
ke sono le mutazioni riflesse? :asd:
cmq secondo me la mutazione di un attributo a volte è necessaria per semplificare il design :O
sò della filosofia ke se devo cambiare un attributo x fare quello ke mi serve lo cambio.. non mi faccio mille seghe mentali sulle mutazioni riflesse ke non ho manco idea di cosa siano :asd:
e cmq è mercoledì ancora :O
:asd:

PGI-Bis
12-09-2007, 22:03
:D

Non è una sega mentale da farsi. E' un'interpretazione per così dire formale di quello che già si fa.

La mutazione riflessa è semplicemente questo:

object Pippo {
void pippa() {}
}

object Beppe {
void beppa() {
new Pippo().pippa();
}
}

Ora prendi Pippo e cambia qualcosa (mutazione). In questo caso eliminiamo "pippa()".

object Pippo {}

Bene, (la definizione di) Pippo è cambiata. Il cambiamento subito da Pippo si riflette, si propaga anche a Beppe. Ecco, questa è una mutazione riflessa. Niente di più e niente di meno. E' un cambiamento in una definizione (l'insieme di dichiarazioni che individuano Pippo) che causa un cambiamento in un'altra definizione (l'insieme di dichiarazioni che individuano Beppe).

^TiGeRShArK^
12-09-2007, 22:09
:D

Non è una sega mentale da farsi. E' un'interpretazione per così dire formale di quello che già si fa.

La mutazione riflessa è semplicemente questo:

object Pippo {
void pippa() {}
}

object Beppe {
void beppa() {
new Pippo().pippa();
}
}

Ora prendi Pippo e cambia qualcosa (mutazione). In questo caso eliminiamo "pippa()".

object Pippo {}

Bene, (la definizione di) Pippo è cambiata. Il cambiamento subito da Pippo si riflette, si propaga anche a Beppe. Ecco, questa è una mutazione riflessa. Niente di più e niente di meno. E' un cambiamento in una definizione (l'insieme di dichiarazioni che individuano Pippo) che causa un cambiamento in un'altra definizione (l'insieme di dichiarazioni che individuano Beppe).
capito :p
però lo stesso continuo a non spiegarmi l'utilità.. :mbe:
qdo giocavo con i lego è normale ke avolte sostituendo un pezzo dovevo modificare il design di tutto il sistema...
era un prezzo da pagare x ottenere esattamente quello ke volevo...
e onestamente non vedo tantissime differenze tra la OOP e il giocare ai lego :D

k0nt3
12-09-2007, 22:12
a volte ho la sensazione che la programmazione OO è più simile al domino :asd: :rotfl: ok basta dormo

PGI-Bis
12-09-2007, 22:18
Tu [tigershark] insisti a voler vedere la faccenda come una sorta di norma che ti dice quello che devi fare e quello che non devi fare. Non è così.

Quello che ricavi da questo particolare aspetto dell'orientamento agli oggetti è la risposta alla domanda: se cambio questo pezzo qui, cosa succede?

Se nel tuo progetto c'era scritto che quel pezzo era liberamente rimpiazzabile e nel tuo codice risulta che cambiando quel pezzo va tutto a rotoli sai che c'è un problema di corrispondenza.

E quanto più ti pare ovvio, tanto più siamo sulla strada giusta. Si potrebbe dire che l'orientamento agli oggetti sia la ricerca del perchè talune cose siano evidenti.

[AGGIUNTA] "Tu Tigershark", non "Tu kont3"

^TiGeRShArK^
12-09-2007, 22:25
Tu [tigershark] insisti a voler vedere la faccenda come una sorta di norma che ti dice quello che devi fare e quello che non devi fare. Non è così.

Quello che ricavi da questo particolare aspetto dell'orientamento agli oggetti è la risposta alla domanda: se cambio questo pezzo qui, cosa succede?

Se nel tuo progetto c'era scritto che quel pezzo era liberamente rimpiazzabile e nel tuo codice risulta che cambiando quel pezzo va tutto a rotoli sai che c'è un problema di corrispondenza.

E quanto più ti pare ovvio, tanto più siamo sulla strada giusta. Si potrebbe dire che l'orientamento agli oggetti sia la ricerca del perchè talune cose siano evidenti.

[AGGIUNTA] "Tu Tigershark", non "Tu kont3"
ah ok ora ho capito :stordita:
praticamente sono cose ke faccio normalmente in maniera inconscia ma senza pormi il problema delle eventuali teorie ke ci stanno dietro :fagiano:

atragon
12-09-2007, 22:25
Torno per un attimo sulla tematica che aveva ispirato il 3d (anche se la discussione ha preso pieghe anche più interessanti) riportando uno spezzone di una vecchia e conosciutissima intervista a Torvalds in cui si dimostra più diplomatico (direi più bugiardo a questo punto)

In molti si chiedono come mai il kernel è scritto in C e non in C++. Quali sono i motivi contrari all'uso del C++ nel kernel?

Il C++ avrebbe permesso di usare alcune funzionalità del compilatore che mi sarebbero piaciute, in effetti il C++ è stato usato per un breve lasso di tempo, poco prima di distribuire Linux-1.0, ma non si è rivelata una scelta molto utile e non credo che ci proveremo ancora in futuro, per svariate ragioni.

Un motivo è semplicemente che il C++ è molto più complesso del C, e il compilatore spesso fà cose di nascosto dal programmatore che non sono affatto ovvie quando si guarda il codice localmente. Sì, si possono evitare cose come le classi virtuali e quindi semplificare la situazione, ma la questione è semplicemente che il C++ permette molte cose che il C non permette, e questo può rendere più difficile successivamente trovare le cause dei problemi.

Un altro motivo della scelta è collegato al precedente, e si tratta della velocità e della stabilità dei compilatori. Il C++, essendo un linguaggio molto più coplesso, ha una propensione per avere compilatori con molti più errori, inoltre la compilazione è solitamente più lenta. Questa può essere considerata una questione di implementazione del compilatore, ma la complessità di fondo del linguaggio è certamente un cosa che può essere considerata oggettivamente dannosa per lo sviluppo del kernel.

^TiGeRShArK^
12-09-2007, 22:31
Torno per un attimo sulla tematica che aveva ispirato il 3d (anche se la discussione ha preso pieghe anche più interessanti) riportando uno spezzone di una vecchia e conosciutissima intervista a Torvalds in cui si dimostra più diplomatico (direi più bugiardo a questo punto)

In molti si chiedono come mai il kernel è scritto in C e non in C++. Quali sono i motivi contrari all'uso del C++ nel kernel?

Il C++ avrebbe permesso di usare alcune funzionalità del compilatore che mi sarebbero piaciute, in effetti il C++ è stato usato per un breve lasso di tempo, poco prima di distribuire Linux-1.0, ma non si è rivelata una scelta molto utile e non credo che ci proveremo ancora in futuro, per svariate ragioni.

Un motivo è semplicemente che il C++ è molto più complesso del C, e il compilatore spesso fà cose di nascosto dal programmatore che non sono affatto ovvie quando si guarda il codice localmente. Sì, si possono evitare cose come le classi virtuali e quindi semplificare la situazione, ma la questione è semplicemente che il C++ permette molte cose che il C non permette, e questo può rendere più difficile successivamente trovare le cause dei problemi.

Un altro motivo della scelta è collegato al precedente, e si tratta della velocità e della stabilità dei compilatori. Il C++, essendo un linguaggio molto più coplesso, ha una propensione per avere compilatori con molti più errori, inoltre la compilazione è solitamente più lenta. Questa può essere considerata una questione di implementazione del compilatore, ma la complessità di fondo del linguaggio è certamente un cosa che può essere considerata oggettivamente dannosa per lo sviluppo del kernel.
:mbe:
ha una visione *lievemente* particolare torvalds :stordita:

PGI-Bis
12-09-2007, 22:36
Posta in modo pacato diventa discutibile: nel senso che se ne può discutere. Un primo argomento di discussione potrebbe essere: complesso, complesso, complesso, ok, ma perchè sarebbe così complesso? Dove sono questi punti di complessità?

La mia impressione è che di fronte a C++ si tenda a dire "complesso" senza poi andare a specificare dove e come per il timore di sentirsi dire "non è vero la regola è diversa".

Risposta che sarebbe, paradossalmente, una dimostrazione di complessità.

^TiGeRShArK^
12-09-2007, 22:38
Posta in modo pacato diventa discutibile: nel senso che se ne può discutere. Un primo argomento di discussione potrebbe essere: complesso, complesso, complesso, ok, ma perchè sarebbe così complesso? Dove sono questi punti di complessità?

La mia impressione è che di fronte a C++ si tenda a dire "complesso" senza poi andare a specificare dove e come per il timore di sentirsi dire "non è vero la regola è diversa".

Risposta che sarebbe, paradossalmente, una dimostrazione di complessità.
e tra l'altro se porprio vogliamo fare i pignoli è oggettivamente + semplice della programmazione in c... :fagiano:

k0nt3
12-09-2007, 22:45
penso che possa servire questo punto di vista:
The software industry has come a long way since the C language was invented. Many new concepts were added to the language with C++, but backwards compatibility with C was maintained, including compatibility with nearly all the weaknesses of the original design. There have been many attempts to fix those weaknesses, but the compatibility issue frustrates it. Meanwhile, both C and C++ undergo a constant accretion of new features. These new features must be carefully fitted into the existing structure without requiring rewriting old code. The end result is very complicated - the C standard is nearly 500 pages, and the C++ standard is about 750 pages! C++ is a difficult and costly language to implement, resulting in implementation variations that make it frustrating to write fully portable C++ code.
C++ programmers tend to program in particular islands of the language, i.e. getting very proficient using certain features while avoiding other feature sets. While the code is usually portable from compiler to compiler, it can be hard to port it from programmer to programmer. A great strength of C++ is that it can support many radically different styles of programming - but in long term use, the overlapping and contradictory styles are a hindrance.
C++ implements things like resizable arrays and string concatenation as part of the standard library, not as part of the core language. Not being part of the core language has several suboptimal consequences.

^TiGeRShArK^
12-09-2007, 22:46
penso che possa servire questo punto di vista:
io parlavo della complessità del codice risultante, ovviamente non mi riferivo a quelli ke si sono dovuti fare il culo per mantenere la retrocompatibilità col C :asd:

PGI-Bis
12-09-2007, 22:50
Anche lì cosa "osano" dire? Che lo standard di C++ è di 250 pagine più lungo di quello di C++. Caspiteronzola. Ma perdiana se hanno una critica da fare che la facciano chiara e tonda. Tendono a, può essere difficile, diverse conseguenze non ottimali... ma parliamo di queste conseguenze. E se verrà giù il mondo lo aspetteremo con gli ombrelli aperti.

k0nt3
12-09-2007, 22:58
però in quelle parole si accenna a cosa rende il C++ complesso da gestire sia per il compilatore che per il programmatore.. principalmente:
- C++ è difficile e costoso da implementare (lo standard è di 750 pagine :eek: ma penso che non sia questa l'argomentazione principale visto che l'autore della frase è uno che ha implementato sia un compilatore C++ che uno C)
- i programmatori si specializzano nell'uso di alcune features e evitano di usarne certe altre (credo che più che per questioni di antipatia è per via del fatto che sapere usare il C++ a tutto campo abbastanza difficile da quanto è vasto)
- supporta diversi paradigmi e stili di programmazione che si sovrappongono e si contraddicono rompendo un pò i cosiddetti
- le conseguenze subottimali di cui sopra http://www.digitalmars.com/d/cppstrings.html :O

^TiGeRShArK^
12-09-2007, 23:02
però in quelle parole si accenna a cosa rende il C++ complesso da gestire sia per il compilatore che per il programmatore.. principalmente:
- C++ è difficile e costoso da implementare (lo standard è di 750 pagine :eek: ma penso che non sia questa l'argomentazione principale visto che l'autore della frase è uno che ha implementato sia un compilatore C++ che uno C)
- i programmatori si specializzano nell'uso di alcune features e evitano di usarne certe altre (credo che più che per questioni di antipatia è per via del fatto che sapere usare il C++ a tutto campo abbastanza difficile da quanto è vasto)
- supporta diversi paradigmi e stili di programmazione che si sovrappongono e si contraddicono rompendo un pò i cosiddetti
- le conseguenze subottimali di cui sopra http://www.digitalmars.com/d/cppstrings.html :O
e scusa se te lo dico..
ma secondo te sono meglio le stringhe di c++ o gli array di char di c? :asd:

k0nt3
12-09-2007, 23:09
e scusa se te lo dico..
ma secondo te sono meglio le stringhe di c++ o gli array di char di c? :asd:
direi le stringhe di java o gli array di char del D :O
comunque in generale non ho mai avuto tutti questi problemi con gli array di char del C.. sono solo un pochino più macchinosi da gestire :stordita:

^TiGeRShArK^
12-09-2007, 23:11
direi le stringhe di java o gli array di char del D :O
comunque in generale non ho mai avuto tutti questi problemi con gli array di char del C.. sono solo un pochino più macchinosi da gestire :stordita:

vabbè..
pure io mi divertivo a programmare i PLC in laboratorio all'univ direttamente in Ladder anzikè passare prima per il listato in alto livello dell'SFC..
ma questo non vuol certo dire ke programmare direttamente in ladder sia meno complesso di programmare in SFC :asd:

PGI-Bis
12-09-2007, 23:11
Il sito di D mi pare oltremodo afflitto da celopiùlunghismo. Io penso che una lingua debba essere buona in sè. Questo continuo riferirsi al fatto che la stringhe di D siano meglio di quelle di C++, e ha meno linee di B e ha più punti di A... mah, è un atteggiamento che mi lascia perplesso.

k0nt3
12-09-2007, 23:18
Il sito di D mi pare oltremodo afflitto da celopiùlunghismo. Io penso che una lingua debba essere buona in sè. Questo continuo riferirsi al fatto che la stringhe di D siano meglio di quelle di C++, e ha meno linee di B e ha più punti di A... mah, è un atteggiamento che mi lascia perplesso.
ci sono dei punti in quella pagina (e non solo) che bisogna saltare a piè pari perchè sono minchiate colossali, ma in generale direi che c'è un fondo di verità
è pubblicità comunque.. io mi sono limitato a riportare quell'opinione

cdimauro
13-09-2007, 07:18
Torno per un attimo sulla tematica che aveva ispirato il 3d (anche se la discussione ha preso pieghe anche più interessanti) riportando uno spezzone di una vecchia e conosciutissima intervista a Torvalds in cui si dimostra più diplomatico (direi più bugiardo a questo punto)

In molti si chiedono come mai il kernel è scritto in C e non in C++. Quali sono i motivi contrari all'uso del C++ nel kernel?

Il C++ avrebbe permesso di usare alcune funzionalità del compilatore che mi sarebbero piaciute, in effetti il C++ è stato usato per un breve lasso di tempo, poco prima di distribuire Linux-1.0, ma non si è rivelata una scelta molto utile e non credo che ci proveremo ancora in futuro, per svariate ragioni.

Un motivo è semplicemente che il C++ è molto più complesso del C, e il compilatore spesso fà cose di nascosto dal programmatore che non sono affatto ovvie quando si guarda il codice localmente. Sì, si possono evitare cose come le classi virtuali e quindi semplificare la situazione, ma la questione è semplicemente che il C++ permette molte cose che il C non permette, e questo può rendere più difficile successivamente trovare le cause dei problemi.

Un altro motivo della scelta è collegato al precedente, e si tratta della velocità e della stabilità dei compilatori. Il C++, essendo un linguaggio molto più coplesso, ha una propensione per avere compilatori con molti più errori, inoltre la compilazione è solitamente più lenta. Questa può essere considerata una questione di implementazione del compilatore, ma la complessità di fondo del linguaggio è certamente un cosa che può essere considerata oggettivamente dannosa per lo sviluppo del kernel.
Mi sembra anche giusto: il C++ è un linguaggio troppo complesso per poter stare nella testa di Torvalds & compagni, per cui gli hanno preferito il ben più semplice C, che è masticabile da cani e porci. :asd:

Quanto alla velocità di compilazione, se fosse veramente un problema avrebbe buttato nel cesso il C da EONI e si sarebbe affidato a linguaggi come Pascal & derivati la cui sintassi permette di scrivere compilatori particolarmente veloci in fase di compilazione.

Che dire: un altro post da incorniciare. :asd:

cdimauro
13-09-2007, 07:25
però in quelle parole si accenna a cosa rende il C++ complesso da gestire sia per il compilatore che per il programmatore.. principalmente:
- C++ è difficile e costoso da implementare (lo standard è di 750 pagine :eek: ma penso che non sia questa l'argomentazione principale visto che l'autore della frase è uno che ha implementato sia un compilatore C++ che uno C)
- i programmatori si specializzano nell'uso di alcune features e evitano di usarne certe altre (credo che più che per questioni di antipatia è per via del fatto che sapere usare il C++ a tutto campo abbastanza difficile da quanto è vasto)
- supporta diversi paradigmi e stili di programmazione che si sovrappongono e si contraddicono rompendo un pò i cosiddetti
- le conseguenze subottimali di cui sopra http://www.digitalmars.com/d/cppstrings.html :O
Marketing.

Il D è decisamente più complesso del C++ da implementare perché presenta non poche caratteristiche aggiuntive (e non banali) rispetto a quest'ultimo.

Da questo punto di vista è singolare che venga rinfacciato al C++ di supportare più paradigmi di programmazione, quando in realtà ne ha soltanto due (quello funzionale è praticamente inesistente) e il D ne presenta anche di più (ad esempio la programmazione by contract).

Inoltre proprio perché il D è ben più ricco del C++, i programmatori avranno la tendenza a utilizzare un certo sottoinsieme di caratteristiche che "masticano più facilmente".

Infine sulle stringhe mi sembra la scoperta dell'acqua calda: mi sembra più che normale un linguaggio giovane come il D ne metta a disposizione un modello più semplice e più ad alto livello.

Ribadisco: marketing.

thebol
13-09-2007, 10:51
http://www.artima.com/weblogs/viewpost.jsp?thread=214235

guido risponde sul multithreading in pyton

cdimauro
13-09-2007, 13:10
Il link era stato già postato. :p

thebol
13-09-2007, 13:14
non l'avev visto :asd:

k0nt3
13-09-2007, 13:53
comunque sia io penso che il C è ancora in buon linguaggio per fare certe cose "a contatto con il ferro" per così dire. dove la fase di progettazione è poco importante perchè ci ha già pensato altra gente e si può procedere nell'implementazione sicuri che la struttura base non può essere stravolta (situazione in cui la programmazione OO eccelle).
nella maggiorparte dei casi è utile usare l'approccio OO, non c'è dubbio ma a questo punto il C++ diventa una delle ultime scelte per quanto mi riguarda.
lo userei solo in accoppiata con le librerie QT, ma sapendo bene di lavorare con meno di 1/5 delle potenzialità del linguaggio (quasi alla java per intenderci)

ecco alcuni esempi:
http://www.google.com/codesearch?hl=en&q=+lang:c%2B%2B+show:FpranJJj6Es:XY_nb9af01M:OlHc03TX69A&sa=N&cd=1&ct=rc&cs_p=http://www.codesynthesis.com&cs_f=projects/xsde/documentation/cxx/parser/guide/-015#first
http://www.google.com/codesearch?hl=en&q=+lang:c%2B%2B+show:oUBbQRfAcYA:MiO1lO3tzuA:HyuyXP-kjds&sa=N&cd=2&ct=rc&cs_p=http://cs.anu.edu.au/~Hugh.Fisher/py3d/py3d.tar&cs_f=py3dview/netwrap/Demos/tcpclient.cpp#first
http://www.google.com/codesearch?hl=en&q=+lang:c%2B%2B+show:D1WlP97_m9U:3O2W9aYHPnM:4Si9lcRzO9o&sa=N&cd=18&ct=rc&cs_p=http://www.sgi.com/tech/stl/stdlib_19990830.tar.gz&cs_f=ios.cxx#first
http://www.google.com/codesearch?hl=en&q=+lang:c%2B%2B+amarok+show:X8zdy1isTP4:1YKpSIYumAM:qZxNPJg-0w8&sa=N&cd=3&ct=rc&cs_p=http://ftp.sayclub.com/pub/X/KDE/snapshots/kdeaddons.tar.bz2&cs_f=kdeaddons-669355/kicker-applets/mediacontrol/amarokInterface.cpp#first

se non ci fosse scritto non direi nemmeno che si tratta dello stesso linguaggio di programmazione

qual'è il problema? in teoria nessuno, ma quando si è in tanti a sviluppare qualcosa e uno usa i template, l'altro i puntatori a void, l'altro ancora fa una gerarchia di 10 classi... capite che lavorare in questo modo su un kernel non è il massimo. l'ideale in C++ è sempre usare un sottoinsieme del linguaggio, ma a questo punto sorge il dubbio che il C++ sia sprecato per quello che devi fare. infine non si può nascondere che un compilatore C++ è molto ma molto più complesso di un compilatore C e questo comporta una minore controllo sul risultato finale per forza di cose e una maggiore predisposizione a errori (non necessariamente critici, ma errori). sono cose che nella maggiorparte dei casi non sono così importanti, ma nello sviluppo di un kernel sicuramente lo sono.

parlando del D invece mi piace molto la parte di programmazione by contract (che non è un paradigma vero e proprio ma una metodologia di sviluppo che può accoppiarsi perfettamente con qualsiasi paradigma), la parte relativa allo unit testing e i template mixins.
quest'ultimi li ho appena conosciuti e penso che siano di un'importanza importante :D
chi di voi non pratica il copia-incolla nel tempo libero? sono stato a una conferenza di un professore dell'università di washington in cui si parlava proprio di una ricerca sul copia-incolla condotta da IBM se non sbaglio. si cercava un modo di gestire in maniera centralizzata le varie parti incollate a livello di IDE, mentre il D presenta una soluzione a livello di linguaggio che mi sembra molto utile e elegante (oltre che parametrica).
il problema di fondo dei copia-incolla è che se cambi una riga a una copia dovresti cambiarla anche alle altre, senza contare i possibili errori.. certamente a uno viene da dire che si poteva sicuramente delegare lo spezzone di codice a una funzione, ma vi consiglio un esame di coscienza prima di parlare :stordita: non sempre è naturale farlo e non sempre vi è la consapevolezza di quello che si sta per fare.
chi non ha mai usato il copia-incolla scagli la prima pietra :O

cdimauro
13-09-2007, 14:08
Con ciò vorresti scaricare l'incapacità (persino di organizzazione) dei programmatori sulle spalle di un linguaggio: lo trovo semplicemente ridicolo (non mi riferisco a te, ma al contesto, eh! :)), soprattuto alla luce delle linee guida che lo stesso Torvalds s'è premurato di stilare.

Inoltre se esiste la paura di commettere errori a causa dei costrutti e/o sintassi (anche questa contribuisce) del linguaggio, mi chiedo come ci si possa ancora affidare al C e non ad altri linguaggi procedurali che permettono di effettuare controlli più severi e hanno una sintassi più leggibile (e quindi meno soggetta a errori).

Aggiungiamoci pure la lentezza della compilazione di un linguaggio come il C, e il quadro direi che è completo: è puro masochismo autolesionista continuare così.

P.S.: anch'io ho usato spesso il copia & incolla, ma di errori dovuti a questa pratica me ne sono capitati pochi.

k0nt3
13-09-2007, 14:14
non mi risulta che il C sia più lento da compilare del C++ (anzi)
comunque è vero che il C manca di alcuni costrutti che semplificano la vita, ma per contro ha un maggiore controllo sull'output che si ottiene (quello che intendevo con lavorare a contatto con il ferro). quindi è anche qui questione di esigenze.. non mi sentirei di dire che per questo il C è da buttare

ps. il problema dei copia-incolla riguarda più la manutenibilità del codice, immagina quando devi fare una modifica a una copia.. nel 99% dei casi vorresti farla anche alle altre copie (che magari non sono nemmeno copie esatte e presentano alcune variazioni parametriche) :fagiano:

k0nt3
13-09-2007, 14:18
Con ciò vorresti scaricare l'incapacità (persino di organizzazione) dei programmatori sulle spalle di un linguaggio: lo trovo semplicemente ridicolo (non mi riferisco a te, ma al contesto, eh! :)), soprattuto alla luce delle linee guida che lo stesso Torvalds s'è premurato di stilare.

il linguaggio potrebbe venire incontro però :muro: IMHO :D

cdimauro
13-09-2007, 14:25
non mi risulta che il C sia più lento da compilare del C++ (anzi)
Infatti mi riferivo ad altri linguaggi.
comunque è vero che il C manca di alcuni costrutti che semplificano la vita, ma per contro ha un maggiore controllo sull'output che si ottiene (quello che intendevo con lavorare a contatto con il ferro).
Ce l'hanno anche altri linguaggi (procedurali e non).
quindi è anche qui questione di esigenze.. non mi sentirei di dire che per questo il C è da buttare
Dopo tutto quello che abbiamo scritto, non trovo delle motivazioni valide per continuare a usarlo.
ps. il problema dei copia-incolla riguarda più sulla manutenibilità del codice, immagina quando devi fare una modifica a una copia.. nel 99% dei casi vorresti farla anche alle altre copie (che magari non sono nemmeno copie esatte e presentano alcune variazioni parametriche) :fagiano:
Dipende da come strutturi il codice. Quando ci sono pattern che si ripetono, puoi sempre infilarli in un modulo / package a cui attingere, magari con delle classi astratte da cui ereditare.
il linguaggio potrebbe venire incontro però :muro: IMHO :D
E allora perché continuare a usare il C? Altri linguaggi procedurali permettono di sviluppare con meno probabilità di commettere errori.

PGI-Bis
13-09-2007, 14:32
con meno di 1/5 delle potenzialità del linguaggio (quasi alla java per intenderci)

Che fa, Generale k0nt3, ammassa truppe al confine?

k0nt3
13-09-2007, 14:40
Dipende da come strutturi il codice. Quando ci sono pattern che si ripetono, puoi sempre infilarli in un modulo / package a cui attingere, magari con delle classi astratte da cui ereditare.
sembra facile ma sappiamo tutti che non sempre (per non dire quasi mai) si può sostituire il copia-incolla con qualcosa che lo rappresenta nel linguaggio (almeno non con altrettanta semplicità).. non si tratta di intere classi, ma di spezzoni di codice che si ripetono e per altro nemmeno sempre nella stessa maniera (di solito sono parametrici sul tipo e/o nome della variabile) per cui è anche difficile usare delle funzioni

E allora perché continuare a usare il C? Altri linguaggi procedurali permettono di sviluppare con meno probabilità di commettere errori.
se ci sono dei linguaggi che ti proteggono da eventuali errori significa che fanno qualcosa al posto tuo, che a sua volta significa che hai tolto un pochino di controllo sull'output.
penso ancora che sia da valutare di volta in volta, non si può dire a priori il C di sicuro no.
per me è l'ideale per fare certe cose straconosciute in cui la progettazione e l'astrazione non svolgono ruoli importanti
comunque sia so che non finiremmo mai di discutere anche perchè a te non piace la sintassi c-like mentre io la trovo comoda ;)

k0nt3
13-09-2007, 14:41
gioco la carta "aumenta produzione" e resto in difesa della capitale :O

cdimauro
13-09-2007, 14:56
sembra facile ma sappiamo tutti che non sempre (per non dire quasi mai) si può sostituire il copia-incolla con qualcosa che lo rappresenta nel linguaggio (almeno non con altrettanta semplicità).. non si tratta di intere classi, ma di spezzoni di codice che si ripetono e per altro nemmeno sempre nella stessa maniera (di solito sono parametrici sul tipo e/o nome della variabile) per cui è anche difficile usare delle funzioni
Con Python mi viene molto comodo, invece: il fatto che è amorfo permette già di risolvere un certo problema senza preoccuparti troppo del tipo di dati su cui opera.

Di recente mi sto sbizzarrendo nell'individuare partner ricorrenti da trasformare in decoratori.
Ad esempio, per il log della chiamata a qualunque metodo di una classe (ma anche di funzioni) mi è sufficiente preprendere @log(Log) e pensa a tutto il decoratore. Ad esempio:
@log(Log)
def Pippo(self, Pluto, Topolino, Minnie, *Args, **Keys)
appende nel file di log che è stato aperto come Log una riga che riporta il nome del metodo chiamato (Pippo) e a seguire tutti i suoi parametri.

In tutti i miei sorgenti in cui avevo bisogno di effettuare del logging adesso trovi l'uso di questo decoratore. Il bello è che il codice è completamente centralizzato. Infatti ho avuto bisogno di loggare, oltre ai parametri di input, anche il risultato, e mi è bastato modificare il decoratore aggiungendo un parametro e il gioco è fatto:
@log(Log, LogResult = True)
def Pippo(self, Pluto, Topolino, Minnie, *Args, **Keys)
Questo inserisce nel log un'altra riga col risultato della chiamata a Pippo (sempre che non venga scatenata un'eccezione al suo interno, sia chiaro).
se ci sono dei linguaggi che ti proteggono da eventuali errori significa che fanno qualcosa al posto tuo, che a sua volta significa che hai tolto un pochino di controllo sull'output.
Non è detto. Pensa alla funzione scanf del C: se invece del puntatore alla variabile che deve conservare il valore, metti soltanto il nome della variabile, succede un disastro.

In Pascal con l'uso del qualificatore VAR pensa il compilatore a passare sempre il puntatore.

Non hai perso nessun controllo, perché sei TU che hai detto al compilatore di aver SEMPRE bisogno di un riferimento e non di un valore, e hai la garanzia che il compilatore farà il controllo per te, e questo già a livello di compilazione (invece col C te ne saresti accorto a runtime, e soltanto se fosse generato un segmentation fault oppure il programma manifestasse un comportamento anomalo).
penso ancora che sia da valutare di volta in volta, non si può dire a priori il C di sicuro no.
Ripeto: non vedo motivi per continuare a usarlo, se non per la sua diffusione.
per me è l'ideale per fare certe cose straconosciute in cui la progettazione e l'astrazione non svolgono ruoli importanti
comunque sia so che non finiremmo mai di discutere anche perchè a te non piace la sintassi c-like mentre io la trovo comoda ;)
Non è soltanto questione di sintassi: col C posso anche definirmi delle macro per "simulare" l'uso delle keyword del Pascal, ma questo non mi permette di ottenere i costrutti che questo linguaggio mi mette a disposizione (vedi anche sopra).

PGI-Bis
13-09-2007, 15:18
"decoratore" è il nome carino che si da ad un preprocessore.

cdimauro
13-09-2007, 15:28
Ma è una funzione, non una macro. ;)

Per maggiori informazioni: http://www.python.org/dev/peps/pep-0318/ :)

PGI-Bis
13-09-2007, 15:37
Non è preprocessing :fagiano:. Sono stato tratto in inganno dalla somiglianza con l'uso prevalente delle annotazioni Java.

[ps] Ma perchè si sono inventati quella sintassi alternativa? Mi pare di capire che non sia altro che una concatenazione di invocazioni di funzione. O sbaglio?

cdimauro
13-09-2007, 15:53
Non è preprocessing :fagiano:. Sono stato tratto in inganno dalla somiglianza con l'uso prevalente delle annotazioni Java.
In effetti usano lo stesso simbolo. :p
[ps] Ma perchè si sono inventati quella sintassi alternativa? Mi pare di capire che non sia altro che una concatenazione di invocazioni di funzione. O sbaglio?
Sì, si tratta di un'abbreviazione.

Nel caso che ho riportato questo:
@log(Log)
def Pippo(self, Pluto, Topolino, Minnie, *Args, **Keys): pass
è equivalente a questo:
def Pippo(self, Pluto, Topolino, Minnie, *Args, **Keys): pass
Pippo = log(Log)(Pippo)
Si tratta di composizione di funzioni.

In particolare una funzione, Pippo, viene definita, ma poi viene data in pasto a un'altra funzione, log, che la manipola e restituisce a sua volta una funzione che prende il posto di Pippo.
Quest'atrocità linguistica si traduce nel fatto che log restituisce una funzione wrapper che opera alcune alterazioni alla funzione originale.

Comunque la prima forma è decisamente più leggibile, e siccome Python è un linguaggio che fa della leggibilità il suo punto di forza, sono stati introdotti i decoratori. :p

PGI-Bis
13-09-2007, 16:03
Leggibilissimo.

cdimauro
13-09-2007, 16:05
Sapendo cos'è un decoratore sicuramente. Altrimenti sarebbe arabo. :asd:

PGI-Bis
13-09-2007, 16:10
Hai centrato il punto della leggibilità. Che vale per tutte le lingue che si dichiarino "più leggibili". Non ti trascino nel solito girone di teorie e pinzillacchere.

cdimauro
13-09-2007, 16:14
Avevo intuito l'ironia. :D

Vero! :)

tomminno
13-09-2007, 18:47
- le conseguenze subottimali di cui sopra http://www.digitalmars.com/d/cppstrings.html :O

Mi chiedo cosa possa mai significare che un linguaggio conosce il tipo string!
Cosa mai può conoscere il linguaggio oltre alla sintassi stessa?

wireless
13-09-2007, 19:01
vorrei dire due cose, piccole piccole: vedo che voi rispetto a me siete nani e giganti insieme. Io, forse, una formichina. Cmq dibattito interessante, penso ora di capire la differenza tra informatica e ingegneria informatica. Aggiungo che forse bisognerebbe aprire un altro topic per il dibattito su tutti questi linguaggi, paradigmi etc...
Su Torvalds, si può dire lo stesso che di Gates e Jobs: non erano "le persone giuste al momento giusto", ma solo "le persone al momento giusto".
Torvalds era uno studente nella media: il caso ha voluto che il suo kernel giocattolo incuriosì la comunità e fece da goccia che fa traboccare il vaso. I tempi erano maturi per cominciare a costruire quel qualcosa che sarebbe stato Linux, sorvolando sulla opinabile qualità. Certo che Linux ha messo in moto tante idee e persone e un modo nuovo di fare prodotti (software), inesistente tutt'ora in altre categoria (mai sentito parlare di progetti per auto o elettronica open-source?). Certo, l'open source c'era già prima di Torvalds e di Linux, ma sono stati loro, per fattori come dire...congiunturali, a scatenare il processo: del resto il kernel GNU Hurd non mi pare abbia avuto successo. Quindi quando Torvalds tira fuori teorie assurde o si incacchia mostra solo quello che è sempre stato, per me.
Per concludere il paragone, chiarisco perchè ho chiamato dentro anche Gates, che non aveva niente di eccezionale tra le mani, ma il fatto che il suo dos fosse distribuito con i primi pc ibm compatibili lo fece diventare leggendario (le cose sono andate un pelino diverse, ma credo che il succo sia questo). Idem per Jobs, che di informatica non capiva nulla o quasi ma aveva ottime intuizioni di marketing, nonchè di immagine, e che da alcuni viene considerato cmq un santone o goru dell'informatica. Uomini...al momento giusto, senza particolari meriti oltre quello di fare ciò che c'era da fare quando andava fatto. Non vi conosco, ma da come scrivete (pgi-bis, cdimauro), immagino che se ci fosse stati voi le cose sarebbero andate meglio. Non è stato così purtroppo.

PGI-Bis
13-09-2007, 23:15
Io sono il verme nella mela mangiata dal gigante sulle cui spalle è seduto il nano. Striscio a terra, ogni tanto mi azzuffo con uno scarrafone, insomma si tira a campare come tutti, sperando sempre che non arrivi quel bastardo di un passero: e ho tre uova a carico, e ci ho il mutuo sul nido e zac, jonny il bruco non l'ha più visto nessuno.

Posso tuttavia dire con serenità che fossi stato io lo sviluppatore di Linux le cose sarebbero andate meglio: oggi avremmo GNU/Hurd.

cdimauro
14-09-2007, 07:39
EDIT: completamente travisato il messaggio di wireless.

PGI-Bis
14-09-2007, 09:51
Abbiamo letto lo stesso messaggio in modi diversi?

cdimauro
14-09-2007, 09:55
Mumble mumble. Non credo. Sono le reazioni ad essere diverse. :p

EDIT: Diciamo che a me ha ispirato il pezzo che ha aggiunto dopo.

RI-EDIT. Sì, avevi ragione: avevamo letto due cose completamente diverse. Anzi, ho del tutto travisato io.

k0nt3
14-09-2007, 10:04
Con Python mi viene molto comodo, invece: il fatto che è amorfo permette già di risolvere un certo problema senza preoccuparti troppo del tipo di dati su cui opera.
certo ma non dimentichiamoci che lo scopo del thread è parlare del C++

Di recente mi sto sbizzarrendo nell'individuare partner ricorrenti da trasformare in decoratori.
mi risulta che il decoratore sia un design pattern, comunque avere un modo per esprimere questo concetto nel linguaggio è molto comodo (fermo restando che l'argomento della discussione (almeno la mia) non era python).
ma anche volendo questo non risolve il problema dei copia-incolla, al massimo il fatto che il linguaggio è amorfo lo può limitare

Non è detto. Pensa alla funzione scanf del C: se invece del puntatore alla variabile che deve conservare il valore, metti soltanto il nome della variabile, succede un disastro.

In Pascal con l'uso del qualificatore VAR pensa il compilatore a passare sempre il puntatore.

Non hai perso nessun controllo, perché sei TU che hai detto al compilatore di aver SEMPRE bisogno di un riferimento e non di un valore, e hai la garanzia che il compilatore farà il controllo per te, e questo già a livello di compilazione (invece col C te ne saresti accorto a runtime, e soltanto se fosse generato un segmentation fault oppure il programma manifestasse un comportamento anomalo).

Ripeto: non vedo motivi per continuare a usarlo, se non per la sua diffusione.

Non è soltanto questione di sintassi: col C posso anche definirmi delle macro per "simulare" l'uso delle keyword del Pascal, ma questo non mi permette di ottenere i costrutti che questo linguaggio mi mette a disposizione (vedi anche sopra).
certo che hai perso un pochino di controllo.. non puoi passare un indirizzo arbitrario alla scanf (beno o male che sia hai sempre perso un pò di controllo)

cionci
14-09-2007, 10:11
ma anche volendo questo non risolve il problema dei copia-incolla, al massimo il fatto che il linguaggio è amorfo lo può limitare
Fammi un esempio in C del codice a cui ti riferisci...

cdimauro
14-09-2007, 10:13
certo ma non dimentichiamoci che lo scopo del thread è parlare del C++

mi risulta che il decoratore sia un design pattern, comunque avere un modo per esprimere questo concetto nel linguaggio è molto comodo (fermo restando che l'argomento della discussione (almeno la mia) non era python).
ma anche volendo questo non risolve il problema dei copia-incolla, al massimo il fatto che il linguaggio è amorfo lo può limitare
Il problema del copia-incolla che hai citato non riguardava strettamente il C++, e mi sembra il testo che hai riportato in merito sia piuttosto eloquente. Infatti è un problema generalizzato, ed era di quello che parlava.

Io ho semplicemente riportato la mia esperienza con Python in merito. ;)
certo che hai perso un pochino di controllo.. non puoi passare un indirizzo arbitrario alla scanf (beno o male che sia hai sempre perso un pò di controllo)
Guarda che alla scanf puoi passare quello che vuoi, ed è proprio per questo che capitano i casini. Esempio:

scanf("%d", 0xC0DEDBAD); /* BOOOM! */

k0nt3
14-09-2007, 10:30
Fammi un esempio in C del codice a cui ti riferisci...
Il problema del copia-incolla che hai citato non riguardava strettamente il C++, e mi sembra il testo che hai riportato in merito sia piuttosto eloquente. Infatti è un problema generalizzato, ed era di quello che parlava.

Io ho semplicemente riportato la mia esperienza con Python in merito. ;)

forse lo spezzettamento della discussione vi ha fatto perdere il filo del discorso e lo capisco.. io ho detto che se dovessi scegliere un linguaggio che mi semplifica la vita non sceglierei il C++ perchè banalmente non me la semplifica.
ho fatto l'esempio del D, come avrei potuto fare qualche esempio in Java o in altri linguaggi che semplificano _realmente_ la vita al programmatore e non solo per finta

Guarda che alla scanf puoi passare quello che vuoi, ed è proprio per questo che capitano i casini. Esempio:

scanf("%d", 0xC0DEDBAD); /* BOOOM! */
potrebbero essere casini o comportamenti voluti.. sta di fatto che in pascal non si può fare mentre in C sì

cdimauro
14-09-2007, 10:47
forse lo spezzettamento della discussione vi ha fatto perdere il filo del discorso e lo capisco.. io ho detto che se dovessi scegliere un linguaggio che mi semplifica la vita non sceglierei il C++ perchè banalmente non me la semplifica.
ho fatto l'esempio del D, come avrei potuto fare qualche esempio in Java o in altri linguaggi che semplificano _realmente_ la vita al programmatore e non solo per finta
Sì, ma nel contesto di cui stavamo discutendo di parlava dei problemi generati dall'uso del copia & incolla, non del fatto che tu preferisci il D al C++. ;)
potrebbero essere casini o comportamenti voluti..
Sbagliare a mettere un & prima del nome della variabile da passare alla scanf è uno degli errori più comuni, secondo forse soltanto allo scambiare l'operatore = con == nei test delle condizioni.

Ed è un errore che in Pascal NON puoi commettere.
sta di fatto che in pascal non si può fare mentre in C sì
Non parlare di cose che non conosci. ;)

Anche in Pascal puoi passare l'indirizzo che vuoi a una procedura (o funzione) che si aspetta un parametro VAR, ma devi costruirtelo a manina (leggi: lo devi fare proprio apposta e con la piena consapevolezza di quel che stai facendo).

Questo te lo lascio come esercizio. :D

cdimauro
14-09-2007, 10:59
Fammi un esempio in C del codice a cui ti riferisci...
Visto che l'esempio non è arrivato, te lo faccio io (ma astrattamente). :D

Immagina di dover implementare una coda.

Con un linguaggio non amorfo hai tre possibilità:
- ti scrivi un pezzo di codice che lo fa per un certo tipo di dato (da conservare) e, quando ti serve per un altro tipo di dato fai un copia & incolla selvaggio :D sostituendo al vecchio tipo quello nuovo che ti serve;
- progetti la classe (o le funzioni) in modo da accettare un puntatore al dato e la sua dimensione (da passargli ogni volta a manina);
- prendi l'esempio precedente e progetti una classe astratta per gestire il dato come coppia puntatore e dimensione del dato (questo da passare una sola volta al costruttore); i suoi discendenti la implementeranno e passeranno al costruttore della classe astratta la dimensione del tipo di dati che gestiscono.

Con un linguaggio amorfo è sufficiente scrivere una sola volta il codice per gestire una coda, e qualunque dato gli verrà passerato lo memorizzerà così com'è. Perché non c'è alcun controllo, da parte del compilatore, sul tipo di dati (in genere i dati sono tutti implementati come puntatori a oggetti).

cionci
14-09-2007, 11:02
E i template non vanno bene ?

k0nt3
14-09-2007, 11:10
Sì, ma nel contesto di cui stavamo discutendo di parlava dei problemi generati dall'uso del copia & incolla, non del fatto che tu preferisci il D al C++. ;)
ho detto perchè il C++ non mi semplifica la vita e perchè il D invece sì, il collegamento era implicito ;)
poi che ci siamo soffermati a discutere sui template mixins è un altro conto

Sbagliare a mettere un & prima del nome della variabile da passare alla scanf è uno degli errori più comuni, secondo forse soltanto allo scambiare l'operatore = con == nei test delle condizioni.

Ed è un errore che in Pascal NON puoi commettere.

Non parlare di cose che non conosci. ;)

Anche in Pascal puoi passare l'indirizzo che vuoi a una procedura (o funzione) che si aspetta un parametro VAR, ma devi costruirtelo a manina (leggi: lo devi fare proprio apposta e con la piena consapevolezza di quel che stai facendo).

Questo te lo lascio come esercizio. :D
se parliamo di sbagliare si può sbagliare in tutti i linguaggi. ci sono linguaggi che riescono a ridurre certi errori gravi e il C non è tra questi, ma nemmeno il C++ del resto. anche torvalds ha detto in quella discussione che se proprio deve scegliere un linguaggio di più alto livello ne usa uno con GC & Co. altro che C++
quello che voglio dire è che il C eccelle proprio quando bisogna fare operazioni di questo tipo. paradossalmente è più difficile farlo in pascal e quindi non si può dire che pascal è superiore al C. dipende da cosa devi fare

cdimauro
14-09-2007, 11:16
E i template non vanno bene ?
Certamente. Per chi ce li ha. :p

k0nt3
14-09-2007, 11:18
E i template non vanno bene ?
no i template li ha anche il D, questa è una cosa in più

tomminno
14-09-2007, 11:20
Visto che l'esempio non è arrivato, te lo faccio io (ma astrattamente). :D

Immagina di dover implementare una coda.

Con un linguaggio non amorfo hai tre possibilità:
- ti scrivi un pezzo di codice che lo fa per un certo tipo di dato (da conservare) e, quando ti serve per un altro tipo di dato fai un copia & incolla selvaggio :D sostituendo al vecchio tipo quello nuovo che ti serve;
- progetti la classe (o le funzioni) in modo da accettare un puntatore al dato e la sua dimensione (da passargli ogni volta a manina);
- prendi l'esempio precedente e progetti una classe astratta per gestire il dato come coppia puntatore e dimensione del dato (questo da passare una sola volta al costruttore); i suoi discendenti la implementeranno e passeranno al costruttore della classe astratta la dimensione del tipo di dati che gestiscono.


- Usi i template o generics :D


Con un linguaggio amorfo è sufficiente scrivere una sola volta il codice per gestire una coda, e qualunque dato gli verrà passerato lo memorizzerà così com'è. Perché non c'è alcun controllo, da parte del compilatore, sul tipo di dati (in genere i dati sono tutti implementati come puntatori a oggetti).

E che succede se io volessi una coda di automobili e nel mezzo mi ci finisce una moto? Tutte le volte che uso elementi di quella coda devo verificare che siano del tipo che mi aspetto.
Se provo ad aprire il cofano ad una moto sicuramente ottengo un pernacchione! :Prrr:

k0nt3
14-09-2007, 11:22
la differenza soprattutto è nello scope.. lo scope di un template-mixins è quello corrente in cui viene chiamato (e non dichiarato come i template).

cdimauro
14-09-2007, 11:25
ho detto perchè il C++ non mi semplifica la vita e perchè il D invece sì, il collegamento era implicito ;)
poi che ci siamo soffermati a discutere sui template mixins è un altro conto
Vabbé, non ne usciamo più. :p
se parliamo di sbagliare si può sbagliare in tutti i linguaggi. ci sono linguaggi che riescono a ridurre certi errori gravi e il C non è tra questi, ma nemmeno il C++ del resto. anche torvalds ha detto in quella discussione che se proprio deve scegliere un linguaggio di più alto livello ne usa uno con GC & Co. altro che C++
Certamente, e l'esempio che ho portato era proprio per questo: evidenziare che il C permette di commettere errori dove gli altri linguaggi lo impediscono alla radice.

Quindi se Torvalds predilige linguaggi che lo aiutano a commettere meno errori, è singolare che continui ancora a lavore col C e si lamenti del C++.
quello che voglio dire è che il C eccelle proprio quando bisogna fare operazioni di questo tipo. paradossalmente è più difficile farlo in pascal e quindi non si può dire che pascal è superiore al C. dipende da cosa devi fare
Ma non vedo cosa ci sarebbe di eccellente. Il C, non essendo provvisto di parametri per riferimento ma esclusivamente per valore, è un linguaggio che si presta a far commettere questo tipo di errori (molto comuni).

E' un suo limite, e non c'è nulla di cui esser contenti, anche perché altri linguaggi permettono entrambe le cose e il programmatore può scegliere in maniera precisa cosa vuole ricevere in input. Perfino nel C++ che tanto bistratta Linus è stato aggiunto il passaggio dei parametri per riferimento (che non riguarda la programmazione oggetti: è una caratteristica a disposizione per qualunque paradigma di programmazione).

cdimauro
14-09-2007, 11:27
- Usi i template o generics :D
Già detto. :)
E che succede se io volessi una coda di automobili e nel mezzo mi ci finisce una moto? Tutte le volte che uso elementi di quella coda devo verificare che siano del tipo che mi aspetto.
Se provo ad aprire il cofano ad una moto sicuramente ottengo un pernacchione! :Prrr:
Bisognerebbe vedere come può finirci una moto in una coda di automobili. :p

cionci
14-09-2007, 11:33
Bisognerebbe vedere come può finirci una moto in una coda di automobili. :p
Ci aiuta la programmazione per interfacce...si estrae l'interfaccia veicolo dagli oggetti moto e auto e poi si fa una coda di veicoli.
Diciamo che magari ci calzerebbe di più una dicitura del tipo: "E se in una coda di veicoli ci finisce una pera ?" :P

k0nt3
14-09-2007, 11:36
Certamente, e l'esempio che ho portato era proprio per questo: evidenziare che il C permette di commettere errori dove gli altri linguaggi lo impediscono alla radice.

Quindi se Torvalds predilige linguaggi che lo aiutano a commettere meno errori, è singolare che continui ancora a lavore col C e si lamenti del C++.

Ma non vedo cosa ci sarebbe di eccellente. Il C, non essendo provvisto di parametri per riferimento ma esclusivamente per valore, è un linguaggio che si presta a far commettere questo tipo di errori (molto comuni).

E' un suo limite, e non c'è nulla di cui esser contenti, anche perché altri linguaggi permettono entrambe le cose e il programmatore può scegliere in maniera precisa cosa vuole ricevere in input. Perfino nel C++ che tanto bistratta Linus è stato aggiunto il passaggio dei parametri per riferimento (che non riguarda la programmazione oggetti: è una caratteristica a disposizione per qualunque paradigma di programmazione).
semplicemente io ritengo che il C sia ancora adatto per fare certe cose "sporche" o di basso livello, semplicemente perchè è pensato per quello. assolutamente non credo che sia il linguaggio da preferire, ma solo che ha ancora qualche campo di applicazione (e aggiungo pure ristretto), mentre voi dite che è completamente da buttare

cdimauro
14-09-2007, 11:40
Ci aiuta la programmazione per interfacce...si estrae l'interfaccia veicolo dagli oggetti moto e auto e poi si fa una coda di veicoli.
Diciamo che magari ci calzerebbe di più una dicitura del tipo: "E se in una coda di veicoli ci finisce una pera ?" :P
Esatto, ma qui il problema è proprio concettuale, eh! :p Tutt'altra cosa rispetto al dimenticarsi un &. :D

cdimauro
14-09-2007, 11:42
semplicemente io ritengo che il C sia ancora adatto per fare certe cose "sporche" o di basso livello, semplicemente perchè è pensato per quello. assolutamente non credo che sia il linguaggio da preferire, ma solo che ha ancora qualche campo di applicazione (e aggiungo pure ristretto), mentre voi dite che è completamente da buttare
Ah, beh, se t'interessano le cose sporche :oink: allora alzo le mani! Il C è quel che fa per te. :D

Se invece t'interessa la programmazione di sistema (quindi anche a basso livello), c'è di meglio, ma già da tempo. ;)

P.S. Porco! :Prrr:

k0nt3
14-09-2007, 11:44
Esatto, ma qui il problema è proprio concettuale, eh! :p Tutt'altra cosa rispetto al dimenticarsi un &. :D
può sempre capitare che per via un carattere digitato male ti finisce una pera in coda al casello.. a me è capitato di vedere un errore del genere

cionci
14-09-2007, 11:46
può sempre capitare che per via un carattere digitato male ti finisce una pera in coda al casello.. a me è capitato di vedere un errore del genere
Ma se ci finisce una pera dovresti avere un errore a tempo di compilazione a meno che tu non faccia un cast del puntatore...

cdimauro
14-09-2007, 11:48
può sempre capitare che per via un carattere digitato male ti finisce una pera in coda al casello.. a me è capitato di vedere un errore del genere
Ed è un errore frequente secondo te? ;)

k0nt3
14-09-2007, 11:48
Ah, beh, se t'interessano le cose sporche :oink: allora alzo le mani! Il C è quel che fa per te. :D

Se invece t'interessa la programmazione di sistema (quindi anche a basso livello), c'è di meglio, ma già da tempo. ;)

P.S. Porco! :Prrr:
eheh :Prrr:
c'è sporcizia e sporcizia comunque :O

k0nt3
14-09-2007, 11:50
Ma se ci finisce una pera dovresti avere un errore a tempo di compilazione a meno che tu non faccia un cast del puntatore...
si parlava del python in questo caso

Ed è un errore frequente secondo te?
per uno che sa programmare in C nemmeno dimenticare un & è così frequente

cdimauro
14-09-2007, 11:58
eheh :Prrr:
c'è sporcizia e sporcizia comunque :O
Appunto. Come dicevo prima, il C è un linguaggio che possono usare cani e porci. :asd:
si parlava del python in questo caso
Sì.
per uno che sa programmare in C nemmeno dimenticare un & è così frequente
Succede anche i programmatori più bravi: non siamo mica delle macchine. ;)

Ma si tratta di errori ben diversi e più comuni rispetto a un grossolano errore di design.

P.S. Io non sono cionci. :read: :Prrr:

k0nt3
14-09-2007, 12:00
dannato copia-incolla! :D

tomminno
14-09-2007, 12:33
Esatto, ma qui il problema è proprio concettuale, eh! :p Tutt'altra cosa rispetto al dimenticarsi un &. :D

Beh ma se il linguaggio non mi dice niente se faccio "codaVeicoli.push(pera)" perchè per lui pera può essere qualsiasi cosa... Magari in pera ci ho messo un auto che ha la forma di una pera, ma potrei averci messo un int o una pera appunto.

tomminno
14-09-2007, 12:37
Ah, beh, se t'interessano le cose sporche :oink: allora alzo le mani! Il C è quel che fa per te. :D

Se invece t'interessa la programmazione di sistema (quindi anche a basso livello), c'è di meglio, ma già da tempo. ;)

P.S. Porco! :Prrr:

Allora perchè non esiste DSP o micro a questo mondo senza il suo compilatore C mentre non esistono per altri linguaggi? Se ci fosse di meglio vista la rapidità di uscita di nuovi DSP a quest'ora avremmo il compilatore per il linguaggio Z.
Perchè il C è l'unico linguaggio usato per questi scopi? Evidentemente di meglio non c'è.

PGI-Bis
14-09-2007, 12:42
Che è sta cosa della pera? E' un coda di macchine, di pere, di ogni cosa... Noi dobbiamo tener presente che l'amorfismo è una qualità dal prezzo eccezionalmente elevato: ciò che in un linguaggio polimorfo è uso in un linguaggio amorfo diventa tentativo d'uso.

Come fai a sapere, in un linguaggio amorfo, se l'oggetto ciccio possiede o non possiede la caratteristica x? Lo presumi. In un linguaggio polimorfo quella presunzione diventa precondizione, espressa nel tipo del riferimento.

Il polimorfismo è una scomoda certezza. Io penso che le certezze in programmazione valgano oro.

tomminno
14-09-2007, 13:09
Che è sta cosa della pera? E' un coda di macchine, di pere, di ogni cosa... Noi dobbiamo tener presente che l'amorfismo è una qualità dal prezzo eccezionalmente elevato: ciò che in un linguaggio polimorfo è uso in un linguaggio amorfo diventa tentativo d'uso.

Come fai a sapere, in un linguaggio amorfo, se l'oggetto ciccio possiede o non possiede la caratteristica x? Lo presumi. In un linguaggio polimorfo quella presunzione diventa precondizione, espressa nel tipo del riferimento.

Il polimorfismo è una scomoda certezza. Io penso che le certezze in programmazione valgano oro.

Infatti, ma si parlava di controlli che un linguaggio come il C non esegue consentendoti di fare le peggio porcate.
Un linguaggio amorfo non può ovviamente controllare se stai mettendo una pera in coda alle macchine, dovremmo quindi definire delle porcate i linguaggi amorfi per questo loro mancato controllo?
Evidentemente no.
In C# ad esempio si è sentito la necessità di introdurre il (non) tipo "var" per consentire di estendere le funzionalità del linguaggio. Evidentemente tipizzare troppo può risultare dannoso.

Mixmar
14-09-2007, 13:11
Che è sta cosa della pera? E' un coda di macchine, di pere, di ogni cosa... Noi dobbiamo tener presente che l'amorfismo è una qualità dal prezzo eccezionalmente elevato: ciò che in un linguaggio polimorfo è uso in un linguaggio amorfo diventa tentativo d'uso.

Come fai a sapere, in un linguaggio amorfo, se l'oggetto ciccio possiede o non possiede la caratteristica x? Lo presumi. In un linguaggio polimorfo quella presunzione diventa precondizione, espressa nel tipo del riferimento.

Il polimorfismo è una scomoda certezza. Io penso che le certezze in programmazione valgano oro.

Scusate, adesso dirò una boiata ma, non sono stato molto attento alla discussione... :stordita:

... ma allora è una sorta di "amorfismo" anche il fatto che nelle Collection di Java "ante-generics" non si conoscesse il tipo degli oggetti (che erano visti tutti come "Object")?

In effetti, anche in quel caso, il controllo si fa a runtime all'atto di popolamento della Collection: a posteriori, possiamo verificare solo se il tipo che arriva è esplicitamente quello con "instanceof" o costrutti simili. Che dovrebbe essere cattiva programmazione OO, in ogni caso.

Che dite? :stordita:

k0nt3
14-09-2007, 13:13
Che dite? :stordita:
dico che quando è uscito java5 ho fatto un paio di salti di gioia :D mi ha risparmiato quella porcata delle liste di Object

cdimauro
14-09-2007, 13:44
Beh ma se il linguaggio non mi dice niente se faccio "codaVeicoli.push(pera)" perchè per lui pera può essere qualsiasi cosa... Magari in pera ci ho messo un auto che ha la forma di una pera, ma potrei averci messo un int o una pera appunto.
Che è sta cosa della pera? E' un coda di macchine, di pere, di ogni cosa... Noi dobbiamo tener presente che l'amorfismo è una qualità dal prezzo eccezionalmente elevato: ciò che in un linguaggio polimorfo è uso in un linguaggio amorfo diventa tentativo d'uso.

Come fai a sapere, in un linguaggio amorfo, se l'oggetto ciccio possiede o non possiede la caratteristica x? Lo presumi. In un linguaggio polimorfo quella presunzione diventa precondizione, espressa nel tipo del riferimento.

Il polimorfismo è una scomoda certezza. Io penso che le certezze in programmazione valgano oro.
Infatti, ma si parlava di controlli che un linguaggio come il C non esegue consentendoti di fare le peggio porcate.
Un linguaggio amorfo non può ovviamente controllare se stai mettendo una pera in coda alle macchine, dovremmo quindi definire delle porcate i linguaggi amorfi per questo loro mancato controllo?
Evidentemente no.
In C# ad esempio si è sentito la necessità di introdurre il (non) tipo "var" per consentire di estendere le funzionalità del linguaggio. Evidentemente tipizzare troppo può risultare dannoso.
Scusate, adesso dirò una boiata ma, non sono stato molto attento alla discussione... :stordita:

... ma allora è una sorta di "amorfismo" anche il fatto che nelle Collection di Java "ante-generics" non si conoscesse il tipo degli oggetti (che erano visti tutti come "Object")?

In effetti, anche in quel caso, il controllo si fa a runtime all'atto di popolamento della Collection: a posteriori, possiamo verificare solo se il tipo che arriva è esplicitamente quello con "instanceof" o costrutti simili. Che dovrebbe essere cattiva programmazione OO, in ogni caso.

Che dite? :stordita:
Semplice: poca coerenza. Da una parte le certezze sono oro, d'altra se ne vorrebbe fare a meno perché sono scomode. :p

Comunque in Python è possibile controllare il tipo dei dati che vengono utilizzati, e regolarsi di conseguenza. Se una funzione si aspetta un intero come parametro basta un isinstance(Parametro, int) e il gioco è fatto.

cdimauro
14-09-2007, 13:45
Allora perchè non esiste DSP o micro a questo mondo senza il suo compilatore C mentre non esistono per altri linguaggi? Se ci fosse di meglio vista la rapidità di uscita di nuovi DSP a quest'ora avremmo il compilatore per il linguaggio Z.
Perchè il C è l'unico linguaggio usato per questi scopi? Evidentemente di meglio non c'è.
Semplice: perché è il più diffuso per questo tipo di compiti, come il PHP lo è per il web, tanto per fare un altro esempio noto.

PGI-Bis
14-09-2007, 13:50
Il "morfismo" è l'identificabilità del tipo di un'espressione. Durante la compilazione, verrebbe da dire.

Una lingua è a-morfa se il tipo dell'espressione non è determinabile. Poli-morfo significa che le espressioni hanno uno o più tipi. Monoformo significa che le espressioni hanno tutte quante lo stesso tipo.

Un insieme di Object non è amorfismo: è un insieme di Object. Amorfo è un insieme di non si sa cosa. Nota che Object un'espressione di tipo Object in Java non è polimorfa: il typesystem di Java non è ricorsivo, in cima c'è Object e fine della storia.

E' polimorfo, ad esempio, un riferimento di tipo String. Ha due tipi: String e Object. E' polimorfo un riferimento di tipo Integer: ha tre tipi, Integer, Number, Object. E così via.

Devo ammettere che con l'arrivo di Java 5 ho faticato anche io a trattenere la mia gioia, di fronte alla possibilità di poter finalmente vedere dichiarazioni di questo genere:

class Ciccio<E, T extends Document & Comparable<? super String> & Map<? extends Comparable<Number>, ? extends Comparable<E>>>

k0nt3
14-09-2007, 14:01
Devo ammettere che con l'arrivo di Java 5 ho faticato anche io a trattenere la mia gioia, di fronte alla possibilità di poter finalmente vedere dichiarazioni di questo genere:

class Ciccio<E, T extends Document & Comparable<? super String> & Map<? extends Comparable<Number>, ? extends Comparable<E>>>
hai ragione, ma a me bastava un:
List<String> list;

o proprio al limite un:
List<List<String>> list;

qualsiasi cosa più complicata di questa la ignoro :p

PGI-Bis
14-09-2007, 14:08
Noi dobbiamo guardare il male e commisurare ad esso la cura. Il male era:

(String)arrayList.get(index);

La cura consta di 50 pagine di teoria dei tipi, in parte eccepite dalla necessità di preservare l'interazione con codice non generico.

In Java 5 mi hanno detto che se ho il raffreddore posso curarmi togliendo la sicura alla granata che mi sono infilato in bocca.

k0nt3
14-09-2007, 14:12
il male era che se ti finiva una pera in coda al casello il compilatore non te lo diceva :fagiano:

cdimauro
14-09-2007, 14:18
Il "morfismo" è l'identificabilità del tipo di un'espressione. Durante la compilazione, verrebbe da dire.

Una lingua è a-morfa se il tipo dell'espressione non è determinabile. Poli-morfo significa che le espressioni hanno uno o più tipi. Monoformo significa che le espressioni hanno tutte quante lo stesso tipo.

Un insieme di Object non è amorfismo: è un insieme di Object. Amorfo è un insieme di non si sa cosa. Nota che Object un'espressione di tipo Object in Java non è polimorfa: il typesystem di Java non è ricorsivo, in cima c'è Object e fine della storia.

E' polimorfo, ad esempio, un riferimento di tipo String. Ha due tipi: String e Object. E' polimorfo un riferimento di tipo Integer: ha tre tipi, Integer, Number, Object. E così via.
Piccola richiesta di delucidazione. In Python il tipo di un'espressione è determinabile, ma a runtime:
>>> a = 'Pippo'
>>> b = 2
>>> c = a * b
>>> c
'PippoPippo'
>>> type(c)
<type 'str'>
>>>
Quindi non sarebbe amorfo.

Non mi pare che l'identificabilità sia una condizione necessaria, per lo meno leggendo la tua prima frase.
Devo ammettere che con l'arrivo di Java 5 ho faticato anche io a trattenere la mia gioia, di fronte alla possibilità di poter finalmente vedere dichiarazioni di questo genere:

class Ciccio<E, T extends Document & Comparable<? super String> & Map<? extends Comparable<Number>, ? extends Comparable<E>>>
[MODE PGI-Bis ON]
Leggibilissimo
[MODE PGI-Bis OFF]
:asd:

cdimauro
14-09-2007, 14:20
Noi dobbiamo guardare il male e commisurare ad esso la cura. Il male era:

(String)arrayList.get(index);
Questo non denota forse l'esigenza di poter avere a disposizione UN codice per gestire qualunque tipo di dato? Anche questo sarebbe un male?
La cura consta di 50 pagine di teoria dei tipi, in parte eccepite dalla necessità di preservare l'interazione con codice non generico.

In Java 5 mi hanno detto che se ho il raffreddore posso curarmi togliendo la sicura alla granata che mi sono infilato in bocca.
:rotfl: :rotfl: :rotfl:

PGI-Bis
14-09-2007, 14:23
il male era che se ti finiva una pera in coda al casello il compilatore non te lo diceva

Che fai, mi prendi per i fondelli?

[AGGIUNTO]

Questo non denota forse l'esigenza di poter avere a disposizione UN codice per gestire qualunque tipo di dato? Anche questo sarebbe un male?

Pure tu?

cdimauro
14-09-2007, 14:39
Che fai, mi prendi per i fondelli?

[AGGIUNTO]

Pure tu?
Non era assolutamente mia intenzione prenderti in giro.

Semplicemente come programmatore m'è capitato non poche volte di avere l'esigenza di manipolare dati di qualunque tipo (l'esempio della lista è un classico).
Coi linguaggi non-amorfi la soluzione è usare un puntatore "generico" (TObject in Delphi, Object in Java, ecc. ecc.) e "sporcarsi le mani" col casting. Con quelli amorfi non serve perché i costrutti accettano qualunque tipo.

Da ciò, non penso che aver bisogno di una struttura che manipoli dati di qualunque tipo sia un male. Tutto qui. :)

k0nt3
14-09-2007, 14:44
ah nemmeno io avevo intenzione di prendere in giro qualcuno.. tuttavia se non si introducono i generics il problema della pera rimane irrisolto

Mixmar
14-09-2007, 16:45
Non era assolutamente mia intenzione prenderti in giro.

Semplicemente come programmatore m'è capitato non poche volte di avere l'esigenza di manipolare dati di qualunque tipo (l'esempio della lista è un classico).
Coi linguaggi non-amorfi la soluzione è usare un puntatore "generico" (TObject in Delphi, Object in Java, ecc. ecc.) e "sporcarsi le mani" col casting. Con quelli amorfi non serve perché i costrutti accettano qualunque tipo.

Da ciò, non penso che aver bisogno di una struttura che manipoli dati di qualunque tipo sia un male. Tutto qui. :)

Altra riflessione probabilmente poco originale... ma non sarebbe meglio, in tal caso, che, anzichè disporre di una funzione/metodo che manipola oggetti "generici" o "amorfi", che l'operazione stessa fosse "scaricata" sull'oggetto stesso, facendo così implementare a ciascun tipo la "propria" versione di una certa operazione?

Adesso mi risponderete che, in generale, questo non è sempre possibile... però forse lo è ma è troppo contorto a livello di programmazione? :stordita:

marco.r
14-09-2007, 21:13
Perdonate se parto con una scarrettata di quote, ma gli ultimi giorni sono stati molto intensi e non ho potuto seguire piu' di tanto la discussione...

sembra facile ma sappiamo tutti che non sempre (per non dire quasi mai) si può sostituire il copia-incolla con qualcosa che lo rappresenta nel linguaggio (almeno non con altrettanta semplicità).. non si tratta di intere classi, ma di spezzoni di codice che si ripetono e per altro nemmeno sempre nella stessa maniera (di solito sono parametrici sul tipo e/o nome della variabile) per cui è anche difficile usare delle funzioni

L' uso del copia-incolla e' sintomo che forse il linguaggio non e' cosi' flessibile come servirebbe. Io programmo per far fare al computer le cose ripetitive, ma se devo ripetere lo stesso codice io, perche' non avere un linguaggio che fa anche quello per me ? C++ e' meglio di C a riguardo perche' con i template posso evitare di scrivere lo stesso codice per tipi diversi. C++ di suo e' peggiore di altri linguaggi che hanno un serio supporto alla metaprogrammazione, perche' non posso ad esempio prendere una classe e wrappare ogni metodo con una funzione di logging, lo devo fare a mano metodo per metodo...

PGI-Bis
14-09-2007, 21:26
Il mio "mi prendete per le natiche" era amorevole: sapete che io sono inoffendibile per costituzione.

E' possibile che sia passato inosservato, quindi lo ripeto:

<E, T extends Document & Comparable<? super String> & Map<? extends Comparable<Number>, ? extends Comparable<E>>>

Una cosa come questa sarebbe accettabile se curasse la fame nel mondo, prevenisse la morte o abbassasse le tasse del 40%. Il problema della pera... quella roba che ho scritto là sopra in Java significa qualcosa! Non ci si riesce a credere!

marco.r
14-09-2007, 21:33
Hai centrato il punto della leggibilità. Che vale per tutte le lingue che si dichiarino "più leggibili". Non ti trascino nel solito girone di teorie e pinzillacchere.
( So che con questo mi attirero' l'ennesimo pistolotto :D, ma abbocco ugualmente all'amo :p )
La lingua deve essere leggibile per chi la conosce, non per il lettore casuale.
Per leggibile, nel caso dei linguaggi di programmazione perlomeno, intendo dire che trasmette chiaramente e in modo non ambiguo il suo significato.
La @ del python puo' non piacere ma, per uno che ci programma, puo' voler dire solo una cosa. Essempi di illeggibilita' sono secondo me altri, come ad esempio di implementare operatori che non fanno quello che sembrano (il buon Bjarne ad esempio ha deciso che quelli di bit-shifting andassero bene per scrivere sui canali...) o combinazione malsana di costruttori impliciti in cui pensi di chiamare un certo metodo ma invece ne chiami un altro perche' invece di convertirti il primo argomento lo fa sul secondo...

k0nt3
14-09-2007, 21:43
<E, T extends Document & Comparable<? super String> & Map<? extends Comparable<Number>, ? extends Comparable<E>>>

stento a crederlo :eek: ma cosa #ŧ←¶µđø€→ significa?!
beh ma finchè uno usa List<String> non commette un reato no? :stordita:

PGI-Bis
14-09-2007, 21:53
Ah non ho idea di cosa voglia dire. Probabilmente T deve essere un sottotipo di Document, implementare l'interfaccia Comparable<String> e l'interfaccia Map<Comparable<Number>, Comparable<E>>. Ma se dovessi scommettere...mi darei malato.

List<String> lo capiscono tutti. Ma il linguaggio non dice List<String>. Dice List<ellamiseria>. Uno può dire di conoscere il linguaggio di programmazione Java nella sua versione 5 se, guardando quella roba là sopra, sa anche dirti quale sia il tipo X compatibile con quella dichiarazione. Non si scappa.

Ps.: io ammetto tranquillamente di non conoscere il linguaggio di programmazione Java 5. E' possibile che sia perchè non ho mai capito il documento di Higarashi e Viroli sul tipo esistenziale.

cionci
14-09-2007, 21:57
Meno male che almeno in C++ esistono i typedef ;)
Ora che me lo chiedo...in Java ci sono ? C'è qualcosa per evitare tutto quel malloppone e renderlo più leggibile ?

PGI-Bis
14-09-2007, 22:07
non so quanto i type def possano semplificare le cose.

List<Fragolino>

Uh che bello. E' un list Fragolino. Cos'è Fragolino?

typedef Fragolino ? extends & super & sotter & fotter, soprattutto fotter;

Mi astengo dal pistolottare. Vi chiedo però: che significa leggibile? Leggibile vuol dire "che usa pochi segni"?

PGI-Bis
14-09-2007, 22:35
A scanso di equivoci, io mi dibatto come un caimano ferito di fronte a certe cose perchè penso che esista un sacrosanto diritto di critica ed un altrettanto sacro dovere di esercitarlo. Poi uno programma con quello che c'è: i miracoli non li fa nessuno.

marco.r
14-09-2007, 23:10
In C# ad esempio si è sentito la necessità di introdurre il (non) tipo "var" per consentire di estendere le funzionalità del linguaggio. Evidentemente tipizzare troppo può risultare dannoso.
Non conosco il C# ma non mi sembra che "var" estenda le funzionalita' del linguaggio. Mi sembra piuttosto un modo conciso per dire "ue' compilatore, non rompere e pretendere che metta il tipo che tanto per verificare che non scriva fessere lo devi calcolare pure tu per cui risparmiami la fatica". O giu' di li' :D

marco.r
14-09-2007, 23:18
Semplice: poca coerenza. Da una parte le certezze sono oro, d'altra se ne vorrebbe fare a meno perché sono scomode. :p

Comunque in Python è possibile controllare il tipo dei dati che vengono utilizzati, e regolarsi di conseguenza. Se una funzione si aspetta un intero come parametro basta un isinstance(Parametro, int) e il gioco è fatto.
Il problema e' che e' e' una operazione faticosa (per noi pigri programmatori :D) per cui di solito non si fa (alzi la mano chi usa un linguaggio di scripting e controlla regolarmente il tipo degli oggetti passati.
I loro fautori sostengono che queste cose comunque le si scoprono con i test per cui in pratica li si controlla lo stesso visto che i test bisogna comunque farli... altri ribattono che forse con un linguaggio piu' rigido alcuni test non servono piu'... la questione e' spinosa :p.

marco.r
14-09-2007, 23:48
Ps.: io ammetto tranquillamente di non conoscere il linguaggio di programmazione Java 5. E' possibile che sia perchè non ho mai capito il documento di Higarashi e Viroli sul tipo esistenziale.

[Edit: quanto avevo scritto non era corretto. ]
I tipi esistenziali in se' non sono cosi' male e neanche difficili da capire. Perlomeno se itegrati bene. In altri linguaggi (funzionali) sono meglio amalgamati e non sembrano una cosa posticcia.

cdimauro
15-09-2007, 06:58
Altra riflessione probabilmente poco originale... ma non sarebbe meglio, in tal caso, che, anzichè disporre di una funzione/metodo che manipola oggetti "generici" o "amorfi", che l'operazione stessa fosse "scaricata" sull'oggetto stesso, facendo così implementare a ciascun tipo la "propria" versione di una certa operazione?

Adesso mi risponderete che, in generale, questo non è sempre possibile... però forse lo è ma è troppo contorto a livello di programmazione? :stordita:
No, è la terza soluzione che avevo già scritto qui http://www.hwupgrade.it/forum/showpost.php?p=18693134&postcount=340 :p

cdimauro
15-09-2007, 07:06
Perdonate se parto con una scarrettata di quote, ma gli ultimi giorni sono stati molto intensi e non ho potuto seguire piu' di tanto la discussione...
Ma scherzi? Qui ognuno scrive quando può (e se ha voglia). Anzi, è un piacere leggerti per cui già il fatto che scrivi è una gran cosa. :)
L' uso del copia-incolla e' sintomo che forse il linguaggio non e' cosi' flessibile come servirebbe. Io programmo per far fare al computer le cose ripetitive, ma se devo ripetere lo stesso codice io, perche' non avere un linguaggio che fa anche quello per me ? C++ e' meglio di C a riguardo perche' con i template posso evitare di scrivere lo stesso codice per tipi diversi. C++ di suo e' peggiore di altri linguaggi che hanno un serio supporto alla metaprogrammazione, perche' non posso ad esempio prendere una classe e wrappare ogni metodo con una funzione di logging, lo devo fare a mano metodo per metodo...
Io, se hai visto i miei esempi precedenti, marco ogni metodo con un decoratore che mi sono costruito. Quindi se in una classe ho n metodi che voglio loggare, li devo "decorare" uno a uno.

Sarebbe anche possibile ispezionare una classe a caccia dei metodi che definisce e decorarli tutti automaticamente, ma è una soluzione che non preferisco per due motivi:
- perché NON voglio oppure è inutile che vengano tracciati alcuni metodi (es: un metodo che viene chiamato spesso e che esegue un'operazione accessoria) ;
- perché a volte ho l'esigenza di loggare tipi di informazione diversi (es: di alcune m'interessa anche il risultato; di altre è molto meglio che il risultato non sia loggato perché il file di log crescerebbe in maniera spaventosa; di altre ancora non m'interessa loggare l'ultimo parametro perché è una variabile di contesto usata da ICE e non me ne può fregar di meno; ecc. ecc.).

cdimauro
15-09-2007, 07:26
( So che con questo mi attirero' l'ennesimo pistolotto :D, ma abbocco ugualmente all'amo :p )
La lingua deve essere leggibile per chi la conosce, non per il lettore casuale.
Per leggibile, nel caso dei linguaggi di programmazione perlomeno, intendo dire che trasmette chiaramente e in modo non ambiguo il suo significato.
La @ del python puo' non piacere ma, per uno che ci programma, puo' voler dire solo una cosa. Essempi di illeggibilita' sono secondo me altri, come ad esempio di implementare operatori che non fanno quello che sembrano (il buon Bjarne ad esempio ha deciso che quelli di bit-shifting andassero bene per scrivere sui canali...) o combinazione malsana di costruttori impliciti in cui pensi di chiamare un certo metodo ma invece ne chiami un altro perche' invece di convertirti il primo argomento lo fa sul secondo...
non so quanto i type def possano semplificare le cose.

List<Fragolino>

Uh che bello. E' un list Fragolino. Cos'è Fragolino?

typedef Fragolino ? extends & super & sotter & fotter, soprattutto fotter;

Mi astengo dal pistolottare. Vi chiedo però: che significa leggibile? Leggibile vuol dire "che usa pochi segni"?
Per me sì: io preferisco le parole ai simboli. Fra un "and" e un "&&" preferisco di gran lunga la prima soluzione.

Diciamo che quanto più riesco a leggere i sorgenti in lingua inglese (per quanto non apprezzi assolutamente questa lingua), meglio è.

Un altro esempio è l'uso dell'operatore ternario introdotto in Python 2.5:
Nome = raw_input('Inserisci il tuo nome: ')
print '|-Q______ SBAV SBAV SBAV!' if Nome == 'Letitia Casta' else 'Sei una cozza!'
Lo trovo LEGGERMENTE più leggibile del classico ? usato nei linguaggi C-like. :p

Poi è chiaro che non è sempre così e che un linguaggio può definire dei costrutti che richiedono necessariamente una sua conoscenza approfondita perché non interpretabili in lingua inglese.
E' il caso dei decoratori di cui abbiamo discusso, il cui significato dev'essere per forza di cose noto.

Comunque è anche vero che sull'argomento ho sbagliato io l'esempio, mostrando un uso "più avanzato" di questa caratteristica, che è stata introdotta per eliminare la vecchia e poco leggibile sintassi usata per forzare l'introduzione di metodi statici o di classe.

Se avessi scritto questo:
class Prova:
@staticmethod
def Statico():
print 'Questo è un metodo statico!'

@classmethod
def DiClasse(cls):
print 'Questo è un metodo di classe di %s.' % cls.__name__
molto probabilmente il significato di un decoratore sarebbe stato più abbordabile e meno traumatico per chi ha un'infarinatura di programmazione a oggetti con altri linguaggi.

cdimauro
15-09-2007, 07:31
Il problema e' che e' e' una operazione faticosa (per noi pigri programmatori :D) per cui di solito non si fa (alzi la mano chi usa un linguaggio di scripting e controlla regolarmente il tipo degli oggetti passati.
I loro fautori sostengono che queste cose comunque le si scoprono con i test per cui in pratica li si controlla lo stesso visto che i test bisogna comunque farli... altri ribattono che forse con un linguaggio piu' rigido alcuni test non servono piu'... la questione e' spinosa :p.
Anche perché metodologie di programmazione come il Test Driven Development sono ben poco diffuse (quindi mancando i test, permane il problema della verifica della consistenza di quello s'è scritto).

I test bisognerebbe farli, ma chi li fa? Tanti progetti di cui ho scaricato i sorgenti non sa cosa siano... :muro:

Comunque, sì, usualmente non controllo il tipo degli oggetti passati, a meno che non abbia specificamente l'esigenza di farlo. :D

cdimauro
15-09-2007, 07:43
Dimenticavo: wireless mi ha precisato in PVT cosa intendeva dire col suo messaggio e, come aveva intuito il buon PGI-Bis, avevo preso una cantonata colossale. :asd:

Quindi ho editato i messaggi.

PGI-Bis
15-09-2007, 07:48
E' una divertente coincidenza. Parliamo di leggibilità e assistiamo ad un caso in cui la conoscenza della lingua non è condizione sufficiente all'acquisizione del significato.

k0nt3
15-09-2007, 10:30
L' uso del copia-incolla e' sintomo che forse il linguaggio non e' cosi' flessibile come servirebbe. Io programmo per far fare al computer le cose ripetitive, ma se devo ripetere lo stesso codice io, perche' non avere un linguaggio che fa anche quello per me ? C++ e' meglio di C a riguardo perche' con i template posso evitare di scrivere lo stesso codice per tipi diversi. C++ di suo e' peggiore di altri linguaggi che hanno un serio supporto alla metaprogrammazione, perche' non posso ad esempio prendere una classe e wrappare ogni metodo con una funzione di logging, lo devo fare a mano metodo per metodo...
quindi stai scagliando la prima pietra.. tu sei colui che non usa il copia-incolla?
hai mai trasgredito in python? :D
io non credo che i template e i decoratori siano sufficienti, ma ben vengano opinioni differenti

cionci
15-09-2007, 10:38
E' una divertente coincidenza. Parliamo di leggibilità e assistiamo ad un caso in cui la conoscenza della lingua non è condizione sufficiente all'acquisizione del significato.
Io non la definirei proprio leggibilità...ma comprensibilità. E qualcosa che si avvicina a quanto avviene con una espressione matematica: difficile dire che un'espressione matematica è leggibile, ma diventa comprensibile se conosciamo i simboli.

k0nt3
15-09-2007, 10:41
Dimenticavo: wireless mi ha precisato in PVT cosa intendeva dire col suo messaggio e, come aveva intuito il buon PGI-Bis, avevo preso una cantonata colossale. :asd:

Quindi ho editato i messaggi.
comunque ancora non mi è chiaro cosa l'ha illuminato sulla differenza tra informatica e ingegneria informatica.. poteva renderci partecipi
io avevo capito il suo messaggio come PGI
per intenderci... Torvalds non è uno sprovveduto, programmare qualcosa come GIT nel tempo che ci ha messo lui non è da tutti. che poi si possa contestare in tutti i modi il come, il dove e il quando ok, ma lui l'ha fatto e il risultato è di tutto rispetto.

ps. il kernel GNU Hurd non è mai esistito in realtà, sono solo una manciata di hacker che si scambiano seghe mentali fra loro e non conoscono il famoso detto (nella firma di qualcuno qui nel forum)
"in teoria la pratica e la teoria sono la stessa cosa, ma in pratica no"

cionci
15-09-2007, 10:49
ps. il kernel GNU Hurd non è mai esistito in realtà, sono solo una manciata di hacker che si scambiano seghe mentali fra loro e non conoscono il famoso detto (nella firma di qualcuno qui nel forum)
"in teoria la pratica e la teoria sono la stessa cosa, ma in pratica no"
Sicuro ? Mi risulta che ci sia una distro Debian basata su Hurd.

k0nt3
15-09-2007, 10:57
Sicuro ? Mi risulta che ci sia una distro Debian basata su Hurd.
intendi questi cd aggiornati all'anno scorso? http://ftp.gnuab.org/pub/debian-cd/current/hurd-i386/
è un progetto che non uscirà mai dalla fase alpha purtroppo

ps. quando ho detto che non esiste era mia intenzione esagerare ;)

cionci
15-09-2007, 11:01
intendi questi cd aggiornati all'anno scorso? http://ftp.gnuab.org/pub/debian-cd/current/hurd-i386/
è un progetto che non uscirà mai dalla fase alpha purtroppo

ps. quando ho detto che non esiste era mia intenzione esagerare ;)
A quanto mi risulta hanno in programma di rilasciarlo ufficialmente in Debian Etch nel 2009 anche se le informazioni che ho sono alquanto vecchiotte.

k0nt3
15-09-2007, 11:11
A quanto mi risulta hanno in programma di rilasciarlo ufficialmente in Debian Etch nel 2009 anche se le informazioni che ho sono alquanto vecchiotte.
è impossibile prevedere un rilascio tra due anni.. siamo realisti
sono solamente 20 anni che ci lavorano, cosa vuoi che siano 5 anni più o 5 meno :rotfl:
chiudiamo l'OT va.. se lo rilasciano sul serio non si può che essere contenti :)

marco.r
15-09-2007, 11:53
Sarebbe anche possibile ispezionare una classe a caccia dei metodi che definisce e decorarli tutti automaticamente, ma è una soluzione che non preferisco per due motivi:
Ovviamente mi riferivo ai casi in cui lo si vuole fare :p , e nel tuo caso e' pure piuttosto difficile parlare di copia-incolla. Un esempio abbastanza e' la gestione dei test. Con gli unit test di python dovrei ogni volta che creo una classe di test dovrei crearmi una suite sempre allo stesso modo e aggiungere tale suite all'elenco di quelle create etc., forse non proprio un copia e incolla, ma di una ripetizione mortale. Pero' posso scrivermi un modulo che vada lui in cerca di tutti i file di test, crei automaticamente le suite e le esegua... qualcosa come il seguente:

import unittest
import os
import re
import sys

testRegex = re.compile("test_.*?\.py$")

if len(sys.argv) == 2:
testModules = "test_" + sys.argv[1]
print "Testing",sys.argv[1]
else:
testModules = [ m[:-3] for m in os.listdir(".") if testRegex.match(m) ]
print "Testing", ', '.join(testModules)

def testClasses( moduleName ):
mo = __import__(moduleName)
return [ value for (name,value) in mo.__dict__.items() if name[:4] == "Test" ]


suites = []
for m in testModules:
classSuites = [ unittest.makeSuite(cl) for cl in testClasses(m) ]
suites.append(unittest.TestSuite( classSuites ))

if __name__ == "__main__":
runner = unittest.TextTestRunner()
runner.run( unittest.TestSuite(suites) )

Per progetti non troppo grandi e' tutto quel che serve per aggiungere test senza doverli pure gestire: aggiungi test_qualcosa.py in test/, crei i test in una classe che finisca in Test e sei a posto.
In C++ non lo posso ovviamente fare a meno di ricorrere ad un tool esterno. Era a questo tipo d'uso a cui mi riferivo prima.

marco.r
15-09-2007, 11:58
quindi stai scagliando la prima pietra.. tu sei colui che non usa il copia-incolla?
hai mai trasgredito in python? :D
io non credo che i template e i decoratori siano sufficienti, ma ben vengano opinioni differenti
Nessun linguaggio e' perfetto, per cui una certa quantita' di ripetizione e' inevitabile. Alcuni linguaggi pero' permettono di limitarla.
Dipende anche poi a che scopo e' fatta la copiatura. Se e' per usare il codice iniziale come base di partenza (ovvero le due copie divergeranno nel contenuto e nello scopo) allora non c'e' niente di male nel copiare, il codice sarebbe stato comunque scritto. Diverso se le due copie esprimono lo stesso concetto e devono rimanere sincronizzate. In quel caso piu' si riduce la duplicazione meglio e' e io cerco sempre di farlo, anche se a volte mi porta via un piu' tempo (diciamo che il mio e' il difetto opposto :p).

tomminno
15-09-2007, 13:04
Non conosco il C# ma non mi sembra che "var" estenda le funzionalita' del linguaggio. Mi sembra piuttosto un modo conciso per dire "ue' compilatore, non rompere e pretendere che metta il tipo che tanto per verificare che non scriva fessere lo devi calcolare pure tu per cui risparmiami la fatica". O giu' di li' :D

Il tipo var è stato introdotto per supportare LINQ che è una nuova funzionalità del linguaggio versione 3. Siccome non puoi sapere in anticipo cosa stai trattando (?) allora usi var, ma una volta inizializzata, la variabile è fortemente tipizzata.
Se sto eseguendo una query su un array di stringhe so che il risultato è un array di stringhe, se lo eseguo su una lista di automobili so che il risultato è una lista di automobili.
Quando però ti trovi in mezzo al codice per capire di che tipo è un oggetto var sei costretto ad usare l'intellisense e dedurre il tipo dai metodi che ti vengono propinati, oppure in alternativa andare a studiare il codice per capire che cavolo è, quando si parla di leggibilità...

Ci devono sicuramente essere delle motivazioni più valide alla sua introduzione ma sinceramente mi sfuggono.

marco.r
15-09-2007, 13:30
Il tipo var è stato introdotto per supportare LINQ che è una nuova funzionalità del linguaggio versione 3. Siccome non puoi sapere in anticipo cosa stai trattando (?) allora usi var, ma una volta inizializzata, la variabile è fortemente tipizzata.
Se sto eseguendo una query su un array di stringhe so che il risultato è un array di stringhe, se lo eseguo su una lista di automobili so che il risultato è una lista di automobili.
Quando però ti trovi in mezzo al codice per capire di che tipo è un oggetto var sei costretto ad usare l'intellisense e dedurre il tipo dai metodi che ti vengono propinati, oppure in alternativa andare a studiare il codice per capire che cavolo è, quando si parla di leggibilità...

Ci devono sicuramente essere delle motivazioni più valide alla sua introduzione ma sinceramente mi sfuggono.

Esatto piu' o meno quello che intendevo io :p, ma guarda che anche solo questa come motivazione e' validissima.

^TiGeRShArK^
15-09-2007, 14:03
Dimenticavo: wireless mi ha precisato in PVT cosa intendeva dire col suo messaggio e, come aveva intuito il buon PGI-Bis, avevo preso una cantonata colossale. :asd:

Quindi ho editato i messaggi.
lo immaginavo :asd:

^TiGeRShArK^
15-09-2007, 14:05
E' una divertente coincidenza. Parliamo di leggibilità e assistiamo ad un caso in cui la conoscenza della lingua non è condizione sufficiente all'acquisizione del significato.
:asd:
in effetti l'italiano è MOOOLTO + ambiguo di java :O

:Prrr:

marco.r
15-09-2007, 14:15
E' una divertente coincidenza. Parliamo di leggibilità e assistiamo ad un caso in cui la conoscenza della lingua non è condizione sufficiente all'acquisizione del significato.
Spiegami di che lingua stiamo parlando allora :D, perche' se ti riferisci al caso dei decoratori, una persona che conosca la "lingua Python" non puo' sbagliarsi. Non mi esprimo sul discorso Java visto che ormai non lo tocco piu' da un bel po' di tempo...
Forse intendi dire che dovrebbero essere leggibili per chi conosce la lingua italiana/inglese ? Vero fino ad un certo punto, ovvero per chi inizia, che ha una mappatura piu' diretta con concetti che conosce gia', ma solo fino ad un certo punto.

Dott.Wisem
15-09-2007, 14:39
Dico che questa superiorità è putativa, cioè non dimostrabile nei fatti, non tanto perchè la prospettiva orientata agli oggetti, in quanto modello, è un'approssimazione ma in quanto la realtà che vorremmo approssimare non è chiara.Che significa 'questa superiorità è putativa'? Il termine 'putativo' viene usato per indicare una persona che ricopre un ruolo al posto di un'altra (ad esempio, padre putativo), quindi non riesco a capire l'uso di tale termine nella proposizione sopra menzionata.
E poi, perdonami, ma perché usare dei termini così poco comuni su un forum dai contenuti tecnici? Sembra quasi che si voglia rendere ancor più difficile la comprensione di un ragionamento già di per sé abbastanza intricato...

Mixmar
15-09-2007, 15:07
Che significa 'questa superiorità è putativa'? Il termine 'putativo' viene usato per indicare una persona che ricopre un ruolo al posto di un'altra (ad esempio, padre putativo), quindi non riesco a capire l'uso di tale termine nella proposizione sopra menzionata.

Intuitivamente, il significato di putativo in quel contesto è quello derivato dalla radice latina della parola, cioè "ipotetico" (da "puto", credo, ipotizzo, reputo). Non so se questo uso "filologico" sia parte della lingua italiana, ma forse basta trovare un precedente... :D

^TiGeRShArK^
15-09-2007, 15:15
Spiegami di che lingua stiamo parlando allora :D, perche' se ti riferisci al caso dei decoratori, una persona che conosca la "lingua Python" non puo' sbagliarsi. Non mi esprimo sul discorso Java visto che ormai non lo tocco piu' da un bel po' di tempo...
Forse intendi dire che dovrebbero essere leggibili per chi conosce la lingua italiana/inglese ? Vero fino ad un certo punto, ovvero per chi inizia, che ha una mappatura piu' diretta con concetti che conosce gia', ma solo fino ad un certo punto.
ecco un altro esempio perfettamente calzante di quello ke diceva PGI :asd:
la lingua a cui si riferiva, e che tutti noi conosciamo perfettamente, è l'ITALIANO :D
esso infatti, come hai potuto ben vedere in prima persona, leggendo il tuo post precedente in cui hai perfettamente frainteso (:D), si presta a molteplici interpretazioni e fraintendimenti nonostante noi tutti conosciamo tale linguaggio + ke bene :p
e mi pare che Java sia MOLTO ma MOLTO meno piagato dai fraintendimenti rispetto alla nostra cara e vecchia madrelingua :p

Dott.Wisem
15-09-2007, 15:17
Non in tutti.

Poi, se leggi bene, PGI aveva scritto anche il perché non usarlo. ;)In relazione alla storia dello switch, mi pare assurdo che al giorno d'oggi un programmatore debba preoccuparsi di usare un costrutto piuttosto che un altro, perché per uno dei due il compilatore genera un codice migliore. Io mi aspetto che sia il compilatore a fare tutte le ottimizzazioni del caso, mentre io programmatore dovrei pensare ai miei algoritmi da un punto di vista prettamente concettuale, non dal punto di vista del modo in cui un certo compilatore genera il codice, altrimenti verrebbe parzialmente meno l'utilità di usare un linguaggio ad alto livello. Certo, mi rendo conto che non esiste il compilatore perfetto.

^TiGeRShArK^
15-09-2007, 15:20
In relazione alla storia dello switch, mi pare assurdo che al giorno d'oggi un programmatore debba preoccuparsi di usare un costrutto piuttosto che un altro, perché per uno dei due il compilatore genera un codice migliore. Io mi aspetto che sia il compilatore a fare tutte le ottimizzazioni del caso, mentre io programmatore dovrei pensare ai miei algoritmi da un punto di vista prettamente concettuale, non dal punto di vista del modo in cui un certo compilatore genera il codice, altrimenti verrebbe parzialmente meno l'utilità di usare un linguaggio ad alto livello.
lo switch, l'if/else/else if e quant'altro vanno evitati come la morte quando possibile :p
E non certo per la qualità del codice generato dal compilatore :D

Dott.Wisem
15-09-2007, 15:34
lo switch, l'if/else/else if e quant'altro vanno evitati come la morte quando possibile :p
E non certo per la qualità del codice generato dal compilatore :DBeh, in gran parte degli algoritmi non banali, i costrutti if/then/else e similari sono fondamentali... Ovvio che se è abbastanza ristretto (e finito) il dominio dei valori da confrontare nella condizione dell'if, allora mi posso inventare dei metodi più furbi che, però, mi fanno perdere un bel po' di leggibilità al codice. Quindi, a meno che il fattore efficienza non sia assolutamente critico, io preferisco avere leggibilità (e manutenibilità) del codice e perdere qualcosa in prestazioni, piuttosto che massima efficienza e codice poco comprensibile. Se poi, in futuro, i compilatori riusciranno a fare anche questo tipo di ottimizzazioni (se non le fanno già), ben vengano. Ma nel frattempo non voglio certo perderci il senno. ;)

Dott.Wisem
15-09-2007, 15:42
Intuitivamente, il significato di putativo in quel contesto è quello derivato dalla radice latina della parola, cioè "ipotetico" (da "puto", credo, ipotizzo, reputo). Non so se questo uso "filologico" sia parte della lingua italiana, ma forse basta trovare un precedente... :DSi, ora che mi ci fai pensare, credo anche io che si riferisse ad un sinonimo di 'ipotetico', dalla radice latina della parola.
Comunque, il termine 'putativo' è usato davvero pochissimo, soprattutto come sinonimo di 'ipotetico'.

PGI-Bis
15-09-2007, 16:25
Scegliere cosa fare tramite una mappa mi sembra più sintetico rispetto a scegliere tramite uno switch o una catena di if-else. Essendo inoltre la mappa rappresentata da una variabile possiamo usare il nome di quest'ultima per esprimere un significato in più (a scelta del programmatore).

La scelta tramite una mappa si esprime accedendo al valore associato alla chiave-condizione:

mappa.get(condizione).esegui();

E questo vale a prescindere dal numero di valori che può assumere la condizione. Non è magia ovviamente: bisogna creare nella mappa le associazioni condizione-azione.

Qualche problema possono darlo i linguaggi che non dispongono di un tipo funzione: in questo caso, infatti, alla sinteticità della mappa fa da contraltare la necessità di definire un tipo di oggetti attraverso cui rappresentare l'azione che sarà eseguita.

Dott.Wisem
15-09-2007, 17:14
Scegliere cosa fare tramite una mappa mi sembra più sintetico rispetto a scegliere tramite uno switch o una catena di if-else. [...]Quando le espressioni sono complesse, il mapping inizia a diventare abbastanza rognoso da realizzare. La leggibilità va a farsi benedire. Che poi sia sintetico poco importa, da questo punto di vista (e poi da qualche parte dovrai pur definirlo questo mapping... Quindi la sinteticità si ha solo nel punto del codice in cui usi il mapping.). ;)

^TiGeRShArK^
15-09-2007, 17:24
Quando le espressioni sono complesse, il mapping inizia a diventare abbastanza rognoso da realizzare. La leggibilità va a farsi benedire. Che poi sia sintetico poco importa, da questo punto di vista (e poi da qualche parte dovrai pur definirlo questo mapping... Quindi la sinteticità si ha solo nel punto del codice in cui usi il mapping.). ;)
ma un esempio di un caso in cui una catena di if/else o uno switch sia + leggibile dell'uso di una mappa o della programmazione OO qual'è? :mbe:
onestamente ora come ora mi sfugge :fagiano:

PGI-Bis
15-09-2007, 17:28
...omissis...

In effetti molto potrebbe anche dipendere dallo sforzo necessario per trasformare la condizione in un indice.

E' facile esprimere, ad esempio, l'uguaglianza: usi il valore di controllo come chiave e via. E' meno immediato esprimere la disuguaglianza.

Il grosso vantaggio che vedo nella decisione tramite mappa è il fatto di poter scrivere cosa si sceglie lasciando da parte come la scelta sia avvenuta.

Al che dovrei anche dire, e dico, che se esistesse la necessità di esprimere anche il come allora la mappa non potrebbe essere usata.

Insomma, come molte questioni anche questa della mappa come struttura decisionale andrebbe approfondita per capirne esattamente proprietà e limiti.

cionci
15-09-2007, 17:33
Quando le espressioni sono complesse, il mapping inizia a diventare abbastanza rognoso da realizzare. La leggibilità va a farsi benedire. Che poi sia sintetico poco importa, da questo punto di vista (e poi da qualche parte dovrai pur definirlo questo mapping... Quindi la sinteticità si ha solo nel punto del codice in cui usi il mapping.). ;)
La leggibilità di uno switch all'aumentare del numero di branch diventa pari al mapping, anzi forse minore perché, la leggibilità del mapping diventa istantanea nel punto di definizione del mapping (per il valore pari a X succede questo), mentre quella dello switch si perde all'aumentare della dimensione (si perde la cognizione di quale sia la variabile di confronto in quanto la dimensione dello switch la fa uscire dalla visuale). Inoltre quello che viene messo in un case dello switch è spesso del codice (più statemant). Quello che viene messo in un mapping è un oggetto o, in C, un puntatore a funzione, quindi un'entità comunque singola e che avrà un nome ben definito e magari autocommentante. Per carità, c'è sempre la possibilità di realizzare la stessa cosa nello switch, ma la struttura stessa dello switch è comunque più dispersiva.

^TiGeRShArK^
15-09-2007, 18:11
E' facile esprimere, ad esempio, l'uguaglianza: usi il valore di controllo come chiave e via. E' meno immediato esprimere la disuguaglianza.
infatti io mi riferivo all'uguaglianza..
per la disuguaglianza e controllo tra intervalli di interi ad esempio non ha molto senso..
ma nei casi in cui si debba confrontare l'uguaglianza onestamente non mi viene in mente in alcun caso la maggior leggibilità dello switch :mbe:

Dott.Wisem
15-09-2007, 18:51
infatti io mi riferivo all'uguaglianza..
per la disuguaglianza e controllo tra intervalli di interi ad esempio non ha molto senso..
ma nei casi in cui si debba confrontare l'uguaglianza onestamente non mi viene in mente in alcun caso la maggior leggibilità dello switch :mbe:E infatti io ho parlato di espressioni complesse nel mio post precedente.
Vammi a mappare la condizione (a < b and c != d) e vediamo se poi è più leggibile di un IF THEN ELSE ... Ammesso che tu ci riesca a farne il mapping! :p

E comunque, anche in una situazione di confronto d'uguaglianza, trovo che il mapping sia meno leggibile. Ad esempio:

switch(c)
{
case 0:
// ...fa qualcosa...
break;
case 1:
// ...fa qualcosa...
break;
case 3:
// ...fa qualcosa...
break;
}

In questo codice riesco a capire immediatamente le condizioni e il comportamento del programma in base al verificarsi di esse.

Invece, in questo:

mappa.get(c).esegui();

onestamente ci capisco poco se non sono stato io a scrivere il programma o se non ho mai visto né usato tecniche di mapping in sostituzione dello switch.
Poi c'è da considerare che, per capire cosa fa il programma, devo andare a vedere come è fatta la funzione di mapping, scorrendo nel codice fino a trovare la funzione apposita. Non sempre sinteticità implica maggiore leggibilità. ;)

Dott.Wisem
15-09-2007, 18:53
In effetti molto potrebbe anche dipendere dallo sforzo necessario per trasformare la condizione in un indice.

E' facile esprimere, ad esempio, l'uguaglianza: usi il valore di controllo come chiave e via. E' meno immediato esprimere la disuguaglianza.[...]Bravo, vedo che hai inteso il mio ragionamento. :)
Non tutto si può risolvere con il mapping, quindi è ingiusto imprecare contro un programmatore che usa ancora costrutti classici... Spesso non se ne può fare a meno. Altre volte se ne potrebbe fare a meno ma la leggibilità andrebbe a diminuire e, quando l'efficienza non è una priorità, meglio lasciar perdere certe ottimizzazioni, che farebbero soltanto perder tempo inutilmente.

cionci
15-09-2007, 18:59
switch(c)
{
case 0:
// ...fa qualcosa...
break;
case 1:
// ...fa qualcosa...
break;
case 3:
// ...fa qualcosa...
break;
}

In questo codice riesco a capire immediatamente le condizioni e il comportamento del programma in base al verificarsi di esse.

Invece, in questo:

mappa.get(c).esegui();

onestamente ci capisco poco se non sono stato io a scrivere il programma o se non ho mai visto né usato tecniche di mapping in sostituzione dello switch.
Poi c'è da considerare che, per capire cosa fa il programma, devo andare a vedere come è fatta la funzione di mapping, scorrendo nel codice fino a trovare la funzione apposita. Non sempre sinteticità implica maggiore leggibilità. ;)
Ma le informazioni sono altrove (e cioè molto vicino a quel mappa.get(c).esegui()...

Cioè:

mappa.put(0, new FaiQuesto());
mappa.put(1, new FaiQuestAltro());
mappa.put(2, new FaiQuestAltroAncora());

mappa.get(c).esegui();

Al limite, ma proprio al limite è nel costruttore dell'oggetto.

Dott.Wisem
15-09-2007, 18:59
La leggibilità di uno switch all'aumentare del numero di branch diventa pari al mapping, anzi forse minore perché, la leggibilità del mapping diventa istantanea nel punto di definizione del mapping (per il valore pari a X succede questo), mentre quella dello switch si perde all'aumentare della dimensione (si perde la cognizione di quale sia la variabile di confronto in quanto la dimensione dello switch la fa uscire dalla visuale). Inoltre quello che viene messo in un case dello switch è spesso del codice (più statemant). Quello che viene messo in un mapping è un oggetto o, in C, un puntatore a funzione, quindi un'entità comunque singola e che avrà un nome ben definito e magari autocommentante. Per carità, c'è sempre la possibilità di realizzare la stessa cosa nello switch, ma la struttura stessa dello switch è comunque più dispersiva.Quanto detto sopra nei miei post vale anche per il tuo commento. Esistono dei casi dove il mapping conviene, altri dove non conviene. Quello che mi premeva dire era che non è un vantaggio sempre e comunque. Anzi, io sono per non usarlo quasi mai, se non in casi in cui c'è esigenza di ottimizzazioni estreme. Sul punto della leggibilità non sono d'accordo, in quanto uno switch molto grande può essere benissimamente inglobato in una funzione, così che non dia fastidio nel punto di chiamata.

cionci
15-09-2007, 19:05
Quanto detto sopra nei miei post vale anche per il tuo commento. Esistono dei casi dove il mapping conviene, altri dove non conviene.
Perfettamente d'accordo...lo scopo è sempre quello...usare un costrutto quando conviene.

Dott.Wisem
15-09-2007, 19:07
Ma le informazioni sono altrove (e cioè molto vicino a quel mappa.get(c).esegui()...

Cioè:

mappa.put(0, new FaiQuesto());
mappa.put(1, new FaiQuestAltro());
mappa.put(2, new FaiQuestAltroAncora());

mappa.get(c).esegui();

Al limite, ma proprio al limite è nel costruttore dell'oggetto.A parte che io continuo a preferire la leggibilità del costrutto switch, se le funzioni FaiQuesto, FaiQuestAltro e FaiQuestAltroAncora fossero ognuna di poche linee di codice, e le condizioni da valutare fossero poche, come nel caso dell'esempio, il mapping potrebbe essere perfino meno efficiente, in quanto a run-time ci sarebbero diversi context-switch che con il costrutto switch/case non sarebbero necessari.

cionci
15-09-2007, 19:11
Non ne faccio assolutamente una questione di prestazioni.
Uno switch aumenta la complessità ciclomatica in maniera incredibile.

^TiGeRShArK^
15-09-2007, 19:17
A parte che io continuo a preferire la leggibilità del costrutto switch, se le funzioni FaiQuesto, FaiQuestAltro e FaiQuestAltroAncora fossero ognuna di poche linee di codice, e le condizioni da valutare fossero poche, come nel caso dell'esempio, il mapping potrebbe essere perfino meno efficiente, in quanto a run-time ci sarebbero diversi context-switch che con il costrutto switch/case non sarebbero necessari.
bhè..
un esempio ke ritengo piuttosto calzante riguardo all'uso di altri costrutti al posto di switch &co è ad esempio durante lo sviluppo di un parser (ke poi non abbiamo usato) per costruire un linguaggio ad alto livello ad uso del customer per diamonds.
In quel caso ho trasformato l'intera catena di casi ke sarebbe stata necessaria per eseguire le varie azioni corrispondenti ai comandi in un'unica riga di codice che non faceva altro che chiamare il comando corrispondente caricando al runtime l'oggetto comandoX e esequendo il suo metodo execute.
In quel caso ritengo ke la leggibilità sia aumentata molto perchè per sapere cosa faceva il codice bastava analizzare il metodo execute delle varie classi comando (ke avevano nel nome le informazioni sul comando che eseguivano).
Onestamente ad implementare tutto quello con una catena di switch sarebbe uscita una sbrodolata assurda e incomprensibile :p
cmq vi lascio ke devo tornare al mio programmino ora ke ho scoperto la libreria mechanize :D

^TiGeRShArK^
15-09-2007, 19:19
Non ne faccio assolutamente una questione di prestazioni.
Uno switch aumenta la complessità ciclomatica in maniera incredibile.
zizzì :O
e nel caso ke ho discusso nel post precedente uscivi scemo a seguire schermate e schermate di comandi usando lo switch :p

Dott.Wisem
15-09-2007, 19:28
Non ne faccio assolutamente una questione di prestazioni.
Uno switch aumenta la complessità ciclomatica in maniera incredibile.Nell'esempio di sopra non credo proprio. :p
E comunque la Complessità Ciclomatica è solo un parametro 'indicativo' della complessità di un codice. Si basa soprattutto sulla considerazione che gran parte dei programmi sono pieni zeppi di strutture di controllo. Ovviamente, se usi il mapping, stai semplicemente 'nascondendo' altrove la complessità del codice.

Dott.Wisem
15-09-2007, 19:34
bhè..
un esempio ke ritengo piuttosto calzante riguardo all'uso di altri costrutti al posto di switch &co è ad esempio durante lo sviluppo di un parser (ke poi non abbiamo usato) per costruire un linguaggio ad alto livello ad uso del customer per diamonds.
In quel caso ho trasformato l'intera catena di casi ke sarebbe stata necessaria per eseguire le varie azioni corrispondenti ai comandi in un'unica riga di codice che non faceva altro che chiamare il comando corrispondente caricando al runtime l'oggetto comandoX e esequendo il suo metodo execute.
In quel caso ritengo ke la leggibilità sia aumentata molto perchè per sapere cosa faceva il codice bastava analizzare il metodo execute delle varie classi comando (ke avevano nel nome le informazioni sul comando che eseguivano).
Onestamente ad implementare tutto quello con una catena di switch sarebbe uscita una sbrodolata assurda e incomprensibile :p
Se nel tuo caso hai ottenuto un miglioramento sensibile della leggibilità, allora hai fatto benissimo ad usare il mapping. Inoltre credo che per un parser sia una scelta ottimale anche come prestazioni. ;)

cionci
15-09-2007, 19:34
Sul fatto di nasconderla non sono d'accordo...l'istruzione condizionale di fatto non c'è ed anche a livello di testing diventa tutto più semplice.
Non c'è la possibilità di sbagliare mettendo male un case, non c'è possibilità di sbagliare mettendo male un break...e non mi sembra poco. In questo caso imho la complessità ciclomatica centra in pieno: non essendoci condizioni non c'è possibilità di inserire bug nelle condizioni e nei costrutti per gestire le condizioni.
C'è solamente la possibilità di inserire errori nei vari statement, ma questo c'era anche prima ed è l'unica possibilità di errore che rimane ;)

Dott.Wisem
15-09-2007, 20:21
Sul fatto di nasconderla non sono d'accordo...l'istruzione condizionale di fatto non c'è ed anche a livello di testing diventa tutto più semplice.
Non c'è la possibilità di sbagliare mettendo male un case, non c'è possibilità di sbagliare mettendo male un break...e non mi sembra poco. Che significa "sbagliare mettendo male un case"? Ma perché, quando crei il mapping non puoi commettere errori? Ad esempio, invece di scrivere:

mappa.put(0, new FaiQuesto());

scrivi:

mappa.put(0, new FaiQuestAltro());

Il break, al massimo, può accadere che te lo scordi, se non hai molta esperienza. Ma questo è un problema tipico della sintassi C/C++/Java. In altri linguaggi, il break non è neanche necessario (vedi Ruby).

In questo caso imho la complessità ciclomatica centra in pieno: non essendoci condizioni non c'è possibilità di inserire bug nelle condizioni e nei costrutti per gestire le condizioni.Ma c'è possibilità di inserire bug nel mapping delle condizioni... E se le condizioni sono complesse, i bug potrebbero essere molto rognosi da scovare. Insomma, che la Complessità Ciclomatica diminuisca è certamente vero, ma ciò non implica automaticamente che aumenta la leggibilità e la manutenibilità. Dipende da caso a caso. ;)

cionci
15-09-2007, 20:32
mappa.put(0, new FaiQuesto());

scrivi:

mappa.put(0, new FaiQuestAltro());
Il bug sopra è facilmente rilevabile in fase di testing...

Questo no:

switch(c)
{
...
case 0:
faiQuesto();
case 1:
faiQuestAltro();
break;
....
}

E nemmeno questo è facilmente rilevabile dal testing:
switch(c)
{
...
case 1:
faiQuesto();
case 0:
faiQuestAltro();
break;
....
}
Riepto...è chiaro che se non è facile riuscire a determinare il mapping può essere uno spreco di tempo, soprattutto nel caso in cui le condizioni non sono d'uguaglianza, ma quando è possibile imho è sempre bene applicarlo ;)

Dott.Wisem
15-09-2007, 21:14
I bug che hai menzionato sono legati essenzialmente all'istruzione 'break'. Come ti dicevo prima, esistono diversi linguaggi in cui il suo utilizzo è stato eliminato apposta (il pezzo di codice da eseguire termina con l'inizio di un altro case).
Comunque, data l'alta leggibilità del codice in un costrutto switch, gli errori mostrati nei tuoi ultimi esempi sono molto ben visibili anche ad una rapida lettura. :)

cionci
15-09-2007, 22:11
Comunque, data l'alta leggibilità del codice in un costrutto switch, gli errori mostrati nei tuoi ultimi esempi sono molto ben visibili anche ad una rapida lettura. :)
Anche quando ci sono molti case e ci sono case che volutamente non hanno un break ?

Dott.Wisem
16-09-2007, 02:04
Anche quando ci sono molti case e ci sono case che volutamente non hanno un break ?Se i case sono moltissimi, allora un mapping conviene principalmente per le performance, come nel caso del parser. Se poi a te il codice pare anche più leggibile, tanto di guadagnato. ;)
Per quanto riguarda i case che non hanno un break, in maniera voluta, questa è una orribile pratica di programmazione (consentita da C/C++/Java) che probabilmente non usa più nessuno.

cionci
16-09-2007, 07:45
Per quanto riguarda i case che non hanno un break, in maniera voluta, questa è una orribile pratica di programmazione (consentita da C/C++/Java) che probabilmente non usa più nessuno.
Orribile nemmeno tanto... In C la usavo spesso. Aiuta a diminuire la duplicazione del codice.
Le performance devono essere l'ultima causa di scelta di uno o dell'altro costrutto, lo scopo primario deve essere la manutenibilità e la leggibilità.

k0nt3
16-09-2007, 09:47
Il bug sopra è facilmente rilevabile in fase di testing...

Questo no:

switch(c)
{
...
case 0:
faiQuesto();
case 1:
faiQuestAltro();
break;
....
}

e perchè non sarebbe facilmente rilevabile in fase di testing?

Dott.Wisem
16-09-2007, 09:56
Orribile nemmeno tanto... In C la usavo spesso. Aiuta a diminuire la duplicazione del codice.Diminuire la duplicazione del codice al costo di introdurre potenziali bug e diminuire la leggibilità del codice è una cosa che non consiglierei in un testo di programmazione... Del resto, se in molti linguaggi recenti il 'break' è stato eliminato dallo switch, qualcosa vorrà pur dire...
Le performance devono essere l'ultima causa di scelta di uno o dell'altro costrutto, lo scopo primario deve essere la manutenibilità e la leggibilità.Non è proprio così: talvolta le performance sono una priorità. Metti che sto scrivendo un gioco per una console e mi accorgo che, introducendo un'ottimizzazione, posso migliorare il frame rate da 20 a 30fps, senza abbassare il livello di dettaglio, però al costo di diminuire la leggibilità di un certo pezzo di codice... In questo caso, la leggibilità viene tranquillamente messa da parte. Ma te ne potrei fare tanti altri di esempi... ;)

cionci
16-09-2007, 10:02
e perchè non sarebbe facilmente rilevabile in fase di testing?
Perché solitamente si testa un ramo per volta...e quindi se io faccio un test che mi testa l'esecuzione di faiQuesto() e un test che mi testa l'esecuzione di faiQuestAltro(), ma non si fa un test che mi testa che quando viene eseguito faiQuesto() non mi viene eseguito faiQuestAltro(). Un test del genere solitamente si mette solo per fixare un bug.

PS: parlo di testing e non di debugging

cionci
16-09-2007, 10:10
Non è proprio così: talvolta le performance sono una priorità. Metti che sto scrivendo un gioco per una console e mi accorgo che, introducendo un'ottimizzazione, posso migliorare il frame rate da 20 a 30fps, senza abbassare il livello di dettaglio, però al costo di diminuire la leggibilità di un certo pezzo di codice... In questo caso, la leggibilità viene tranquillamente messa da parte. Ma te ne potrei fare tanti altri di esempi... ;)
Però le performance non si cercano in fase di scrittura del codice, ma quando il codice è già stato scritto, quindi con un profiler...Early optimization is the root of all evil (D. Knuth)
Io sono d'accordo a cambiare un mapping con uno switch per motivi di performance, ma solamente in fase di ottimizzazione.

k0nt3
16-09-2007, 10:11
Perché solitamente si testa un ramo per volta...e quindi se io faccio un test che mi testa l'esecuzione di faiQuesto() e un test che mi testa l'esecuzione di faiQuestAltro(), ma non si fa un test che mi testa che quando viene eseguito faiQuesto() non mi viene eseguito faiQuestAltro(). Un test del genere solitamente si mette solo per fixare un bug.

PS: parlo di testing e non di debugging
ma il problema non è nello switch in se, ma nel break. in questo caso lo rilevi con il test solo se le due azioni interferiscono (e comunque di solito interferiscono). dimenticare il break è come dimenticare di chiudere una parentesi

cionci
16-09-2007, 10:14
ma il problema non è nello switch in se, ma nel break. in questo caso lo rilevi con il test solo se le due azioni interferiscono (e comunque di solito interferiscono). dimenticare il break è come dimenticare di chiudere una parentesi
Appunto è un bug...ma in fase di compilazione la parentesi te ne accorgi che non l'hai messa, mentre il break no ;)

k0nt3
16-09-2007, 10:14
Però le performance non si cercano in fase di scrittura del codice, ma quando il codice è già stato scritto, quindi con un profiler...Early optimization is the root of all evil (D. Knuth)
Io sono d'accordo a cambiare un mapping con uno switch per motivi di performance, ma solamente in fase di ottimizzazione.
sicuro! ma questo non significa che quando programmi devi per forza usare i metodi più lenti perchè ottimizzare è il male..

k0nt3
16-09-2007, 10:34
comunque sia io uso ben poco gli switch, preferisco le catene di if-else if che non tendono trappole per via del break
è vero che le mappe diminuiscono la complessità ciclomatica, ma non teniamo conto del fatto che per implementarle in java bisogna creare un numero di classi esagerato?

ps. un esempio è l'implementazione del menu di diamonds

cionci
16-09-2007, 10:41
è vero che le mappe diminuiscono la complessità ciclomatica, ma non teniamo conto del fatto che per implementarle in java bisogna creare un numero di classi esagerato?
Chiaro che dipende tutto da quello che bisogna fare...

Se devo scrivere una sola istruzione all'interno del blocco della condizione è chiaro che non ricorro nemmeno io al mapping, ma se ci sono molte condizioni e molte istruzioni all'interno delle condizioni, che magari mi obbligano ad estrarre un metodo allora la possibilità di usare un mapping mi viene in mente ;)

cionci
16-09-2007, 10:43
ps. un esempio è l'implementazione del menu di diamonds
Questo non me lo ricordo...comunque mi ricordo benissimo la gestione degli input.
In tutta la gestione degli input non c'era nemmeno un if ;) C'erano molte classi vero, ma fortunatamente i packages di Java funzionano bene.

k0nt3
16-09-2007, 10:51
Chiaro che dipende tutto da quello che bisogna fare...

Se devo scrivere una sola istruzione all'interno del blocco della condizione è chiaro che non ricorro nemmeno io al mapping, ma se ci sono molte condizioni e molte istruzioni all'interno delle condizioni, che magari mi obbligano ad estrarre un metodo allora la possibilità di usare un mapping mi viene in mente ;)
si certo, ma io sono daccordo con te. quello che non mi sembra giusto è escludere a priori l'uso di un costrutto etichettandolo come "il male"
nel menu di diamonds trovi nella classe MainMenu il metodo executeSelectedItem
public void executeSelectedItem(GameLoop loop)
{
menuActionEntered = true;
selectedMenuItem.execute(loop);
}
allora ti devi andare a vedere MenuItem per vedere cosa fa quel metodo
public void execute(GameLoop gameLoop)
{
action().execute(gameLoop);
}
e infine MenuAction che è banalmente
public interface MenuAction
{
void execute(GameLoop loop);
}
ovviamente ci sarà una classe che implementa l'interfaccia per ogni azione e poi la parte che inizializza il menu c'è ed è nascosta in MenuItem (dico nascosta perchè io me l'aspettavo in MainMenu)
public static final MenuItem STORY_MODE = new MenuItem(0,
new MenuActionNone(), "STORY MODE");

public static final MenuItem VERSUS_MODE = new MenuItem(1,
new MenuActionVersusMode(), "VERSUS MODE");

public static final MenuItem ADVANCED_MODE = new MenuItem(2,
new MenuActionNone(), "ADVANCED MODE");

public static final MenuItem CUSTOM_MODE = new MenuItem(3,
new MenuActionNone(), "CUSTOM MODE");

public static final MenuItem OPTIONS = new MenuItem(4,
new MenuActionNone(), "OPTIONS");

public static final MenuItem QUIT = new MenuItem(5, new MenuActionQuit(),
"QUIT");

public static final MenuItem BACK = new MenuItem(6, new MenuActionNone(),
"BACK");

come vedi è stata addirittura creata una gerarchia di classi (MenuAction) quando magari bastava
public void executeSelectedItem(GameLoop loop)
{
menuActionEntered = true;
if(selectedMenuItem == MenuItem.STORY_MODE) {
...
} else if(selectedMenuItem == MenuItem.VERSUS_MODE) {
...
} else if(selectedMenuItem == MenuItem.ADVANCED_MODE) {
...
} else if(selectedMenuItem == MenuItem.CUSTOM_MODE) {
...
} else if(selectedMenuItem == MenuItem.OPTIONS_MODE) {
...
} else if(selectedMenuItem == MenuItem.QUIT) {
...
} else if(selectedMenuItem == MenuItem.BACK) {
...
}
}
e buona notte :D

Dott.Wisem
16-09-2007, 11:07
Però le performance non si cercano in fase di scrittura del codice, ma quando il codice è già stato scritto, quindi con un profiler...Early optimization is the root of all evil (D. Knuth)
Io sono d'accordo a cambiare un mapping con uno switch per motivi di performance, ma solamente in fase di ottimizzazione.Generalmente si fa l'opposto (si cambia uno switch con un mapping), a meno che uno non tenda ad usare il mapping dappertutto, anche per situazioni banali. ;)

PGI-Bis
16-09-2007, 11:28
Il numero elevato di classi che occorre creare in Java un po' per tutto, non solo nel caso delle mappe, deriva dalla struttura del linguaggio. L'elemento fondamentale dell'orientamento agli oggetti è l'oggetto, in Java per definire oggetti occorre usare le classi, ergo tante classi. La sintassi di Java unita alle convenzioni di scrittura del codice Java fanno sì che il codice appaia più voluminoso di quanto potrebbe essere se alcune regole fossero diverse. Cosa più o meno irrilevante per un programmatore che è uno "scrivente a dieci dita".

Io penso che la questione switch-mappa possa essere risolta chiedendosi cosa voglia esprimere il programmatore nel momento in cui si trovi a dover decidere per l'una o per l'altra forma.

Ribadisco la mia opinione: la differenza essenziale che io vedo tra lo switch e la mappa sta nel fatto che mentre lo switch esprime l'atto e il procedimento decisionale, la mappa si limita al primo elemento.

La mappa dice solamente che è presa una decisione. Come questa decisione sia presa è espresso da un'altra parte.

Lo switch, o la catena di if-else, esprime sia l'atto che il procedimento.

Se, nel contesto in cui si deve prendere la decisione, il procedimento è irrilevante, lo switch o l'if-else è sbagliato. Sbagliato per la stessa ragione per cui è sbagliato prendere un kilo di mele dal fruttivendolo dicendo "mi da un kilo di mele prendendole dal cesto a sinistra" se esiste un solo cesto di mele.

In quella particolare forma di comunicazione che il codice sorgente di un programma, l'eliminazione di questo errore oggettivo si scontra con i limiti del linguaggio, delle librerie, dell'economia di produzione del programma eccetera.

k0nt3
16-09-2007, 11:34
se voglio nascondere il procedimento non posso spostare lo switch in una funzione che contiene solo il procedimento?
tipo: prendiLaDecisioneCorretta(parametro);

con l'elevato numero di classi intendevo dire che è più difficile da leggere il codice (vedi esempio sopra)

PGI-Bis
16-09-2007, 11:42
Il fatto di spostare lo switch è venuto in mente anche a me mentre scrivevo. Potrebbe essere un accettabile compromesso nel caso in cui non si riesca ad esprimere "brillantemente" la funzione di hashing che associa la condizione ad un indice.

Crea una ripetizione perchè a quel punto io scriverei da una parte che sto prendendo una decisione e poi lo scriverei nuovamente per poter concretamente decidere. Al che uno, leggendo il codice, potrebbe legittimamente domandarsi: ma perchè cavolo non ha messo lo switch dall'altra parte?

PGI-Bis
16-09-2007, 11:53
Tutti quanti abbiamo una qualche preferenza in base alla quale diciamo che certe cose sono meno leggibili di altre. Sul punto della leggibilità possiamo continuare a tirarci addosso palle di neve fintantochè non stabiliremo cosa si intenda per leggibilità.

Ad esempio io trovo "illeggibile" la forma tramite cui, in Java, si crea un'istanza contestualmente alla dichiarazione di classe. Ha effetti mirabili perchè è quanto di più vicino all'idea di oggetto che si possa avere in Java, sfruttando unicamente la sua sintassi ma non mi "garba".

Sospetto che la ragione per cui mi appare illeggibile stia tanto nell'accrocchio di parentesi che è necessario usare quanto nel modo in cui lo si debba scrivere secondo le convenzioni di codifica.

Cerco di non dirlo perchè è difficile discutere di una sensazione. Può non piacere a me e posso persino capire perchè non mi piaccia ma non posso dire che sia più o meno leggibile in assoluto a meno che io non scopra in esso un carattere che sia difettoso secondo una teoria della comunicazione.

The3DProgrammer
16-09-2007, 12:01
si certo, ma io sono daccordo con te. quello che non mi sembra giusto è escludere a priori l'uso di un costrutto etichettandolo come "il male"
nel menu di diamonds trovi nella classe MainMenu il metodo executeSelectedItem
public void executeSelectedItem(GameLoop loop)
{
menuActionEntered = true;
selectedMenuItem.execute(loop);
}
allora ti devi andare a vedere MenuItem per vedere cosa fa quel metodo
public void execute(GameLoop gameLoop)
{
action().execute(gameLoop);
}
e infine MenuAction che è banalmente
public interface MenuAction
{
void execute(GameLoop loop);
}
ovviamente ci sarà una classe che implementa l'interfaccia per ogni azione e poi la parte che inizializza il menu c'è ed è nascosta in MenuItem (dico nascosta perchè io me l'aspettavo in MainMenu)
public static final MenuItem STORY_MODE = new MenuItem(0,
new MenuActionNone(), "STORY MODE");

public static final MenuItem VERSUS_MODE = new MenuItem(1,
new MenuActionVersusMode(), "VERSUS MODE");

public static final MenuItem ADVANCED_MODE = new MenuItem(2,
new MenuActionNone(), "ADVANCED MODE");

public static final MenuItem CUSTOM_MODE = new MenuItem(3,
new MenuActionNone(), "CUSTOM MODE");

public static final MenuItem OPTIONS = new MenuItem(4,
new MenuActionNone(), "OPTIONS");

public static final MenuItem QUIT = new MenuItem(5, new MenuActionQuit(),
"QUIT");

public static final MenuItem BACK = new MenuItem(6, new MenuActionNone(),
"BACK");

come vedi è stata addirittura creata una gerarchia di classi (MenuAction) quando magari bastava
public void executeSelectedItem(GameLoop loop)
{
menuActionEntered = true;
if(selectedMenuItem == MenuItem.STORY_MODE) {
...
} else if(selectedMenuItem == MenuItem.VERSUS_MODE) {
...
} else if(selectedMenuItem == MenuItem.ADVANCED_MODE) {
...
} else if(selectedMenuItem == MenuItem.CUSTOM_MODE) {
...
} else if(selectedMenuItem == MenuItem.OPTIONS_MODE) {
...
} else if(selectedMenuItem == MenuItem.QUIT) {
...
} else if(selectedMenuItem == MenuItem.BACK) {
...
}
}
e buona notte :D

Non conosco il codice, ma ad occhio questo è un Command da manuale. Il command è uno dei pattern + semplici, flessibili ed utili che io conosca. Se vuoi aggiungere un altro item nel tuo caso devi andare a modificare il codice all'interno del modulo che dichiara executeMenuItem(), mentre con il pattern command basta creare una nuova classe da 0, SENZA modificare il codice del modulo, e inizializzarla. Direi che dal punto di vista del principio open/closed c'è una bella differenza....

ciao

k0nt3
16-09-2007, 12:34
Non conosco il codice, ma ad occhio questo è un Command da manuale. Il command è uno dei pattern + semplici, flessibili ed utili che io conosca. Se vuoi aggiungere un altro item nel tuo caso devi andare a modificare il codice all'interno del modulo che dichiara executeMenuItem(), mentre con il pattern command basta creare una nuova classe da 0, SENZA modificare il codice del modulo, e inizializzarla. Direi che dal punto di vista del principio open/closed c'è una bella differenza....

ciao
se vuoi aggiungere un MenuItem devi creare una nuova classe che eredita MenuAction e modificare la classe MenuItem stessa. mentre con il codice che ho scritto io bastava modificare MainMenu.
il fatto che sia un pattern non significa che sia preferibile sempre e comunque

The3DProgrammer
16-09-2007, 13:01
il fatto che una catena di if/else come scritto sopra violi uno dei principi fondamentali dello sviluppo object oriented e dell'ingegneria del software in generale la rende, almeno dal mio punto di vista, assolutamente inutilizzabile.


Bertrand Meyer gave us guidance as long ago as 1988 when he
coined the now famous open-closed principle. To paraphrase him:

SOFTWARE ENTITIES (CLASSES, MODULES, FUNCTIONS, ETC.)
SHOULD BE OPEN FOR EXTENSION, BUT CLOSED FOR MODIFICATION

When a single change to a program results in a cascade of changes to dependent modules, that program exhibits the undesirable attributes that we have come to associate with “bad” design. The program becomes fragile, rigid, unpredictable and unreusable. The openclosed principle attacks this in a very straightforward way. It says that you should design modules that
never change. When requirements change, you extend the behavior of such
modules by adding new code, not by changing old code that already works.



il fatto che sia un pattern è marginale in questo contesto.

k0nt3
16-09-2007, 13:35
il fatto che una catena di if/else come scritto sopra violi uno dei principi fondamentali dello sviluppo object oriented e dell'ingegneria del software in generale la rende, almeno dal mio punto di vista, assolutamente inutilizzabile.




il fatto che sia un pattern è marginale in questo contesto.
a parte che anche utilizzando il mapping (il fatto che sia un pattern come dici è marginale) devi modificare la classe MenuItem che poveretta non c'entrava niente.
ma il punto principale è che quando uno dice che le catene di if-else if sono dannose a priori commette un errore (e questo sì che lo stabilisco a priori :D )
l'unica parola che conosco io è: dipende
e aggiungo anche "no silver bullet" (prova a darci un'occhiata su gugol ;) )

jappilas
16-09-2007, 13:47
mi ero astenuto finora dal partecipare a questo thread, ma visto che si parla di Diamonds...
Questo non me lo ricordo...me lo ricordo io , implementare il menu è stato il mio primo task in diamonds ;)
siccome all' epoca ero ancora condizionato da anni di c e c++, inizialmente pensai di svolgerlo appunto tramite uno switch - l' implementazione attuale è figlia di un "rimprovero" di fek e del "paradigm shift" che ne seguì e che mi vide ripassare i vari design pattern, scegliere quello più confacente e scrivere le action seguendolo pedissequamente - per forza è un Command da manuale :D
...
...
come vedi è stata addirittura creata una gerarchia di classi (MenuAction) quando magari bastava
public void executeSelectedItem(GameLoop loop)
{
menuActionEntered = true;
if(selectedMenuItem == MenuItem.STORY_MODE) {
...
} else if(selectedMenuItem == MenuItem.VERSUS_MODE) {
...
} else if(selectedMenuItem == MenuItem.ADVANCED_MODE) {
...
} else if(selectedMenuItem == MenuItem.CUSTOM_MODE) {
...
} else if(selectedMenuItem == MenuItem.OPTIONS_MODE) {
...
} else if(selectedMenuItem == MenuItem.QUIT) {
...
} else if(selectedMenuItem == MenuItem.BACK) {
...
}
}
e buona notte :Dma, come all' epoca fece anotare anche fek (che poi rifattorizzò il package del menu aggiungendo le MenuItem), quello sarebbe stato codice C, non Java... e come mi resi subito conto, rispetto al resto del codice di DC o quantomeno rispetto allo stile che il progetto si voleva dare, sarebbe stato un pugno in un occhio
inoltre sarebbe stato meno leggibile e meno manutenibile
se vuoi aggiungere un MenuItem devi creare una nuova classe che eredita MenuAction correzione: che implementa MenuAction, è un' interfaccia (quindi non c'è nulla di cui dover tenere conto per quanto riguarda eventuali comportamenti definiti nella superclasse e quindi ovverriden nella nuova - basta sapere di dover creare una MenuAction concreta) ;)
e modificare la classe MenuItem stessa. la modifica a MenuItem (aggiunta della riga di inizializzazione per la nuova Item) non è sempre necessaria ...
MenuItem è una cosa a parte da MenuAction - non definisce il comportamento delle voci del menu, ma la logica dello stesso (oltre al binding della Action, l' ordine delle voci nel menu (quale attivare in seguito alla pressione dei tasti direzione su/giù))
con lo switch avresti implementato solo il behaviour e avresti dovuto cercare qualche altra soluzione per modificare la selezione corrente - nonchè per riposizionare correttamente lo sprite del menu, infatti:
public static final MenuItem STORY_MODE = new MenuItem(0,
new MenuActionNone(), "STORY MODE");

public static final MenuItem VERSUS_MODE = new MenuItem(1,
new MenuActionVersusMode(), "VERSUS MODE");

public static final MenuItem ADVANCED_MODE = new MenuItem(2,
new MenuActionNone(), "ADVANCED MODE");

public static final MenuItem CUSTOM_MODE = new MenuItem(3,
new MenuActionNone(), "CUSTOM MODE");

public static final MenuItem OPTIONS = new MenuItem(4,
new MenuActionNone(), "OPTIONS");

public static final MenuItem QUIT = new MenuItem(5, new MenuActionQuit(),
"QUIT");

public static final MenuItem BACK = new MenuItem(6, new MenuActionNone(),
"BACK");come puoi notare la singola MenuItem contiene anche un intero: quell' intero viene usato come moltiplicatore dell' offset verticale del frame applicato allo sprite del menu principale - in pratica è la posizione a schermo dell' opzione evidenziata
a parte che anche utilizzando il mapping (il fatto che sia un pattern come dici è marginale) devi modificare la classe MenuItem che poveretta non c'entrava niente.che non c' entri niente non è esatto: la classe MenuItem assume determinate responsabilità, la serie delle MenuAction ne assume altre - in pratica sono le due parti complementari di uno stesso design in cui si cerca di disaccoppiare il behaviour e la logica
modificare MenuItem è richiesto solo se si sta aggiungendo una nuova voce di menu, il che comporta per forza di cose il necessità di rivedere la logica del menu (sequenza e binding), ma finchè ci si limiti a modificare il funzionamento di una MenuAction preesistente, MenuItem non ha motivo di essere toccata
mentre con il codice che ho scritto io bastava modificare MainMenu.il punto era proprio evitare ciò, perchè modificare MainMenu per ridefinire il comportamento delle singole voci avrebbe comportato attribuirgli responsabilità che non gli competevano da design - MainMenu doveva solo fornire un' interfaccia generica per attivare l' opzione selezionata e selezionare la successiva / precedente, ma non non implementare logica concreta di attuazione o selezione

k0nt3
16-09-2007, 14:44
mi ero astenuto finora dal partecipare a questo thread, ma visto che si parla di Diamonds...
me lo ricordo io , implementare il menu è stato il mio primo task in diamonds ;)
siccome all' epoca ero ancora condizionato da anni di c e c++, inizialmente pensai di svolgerlo appunto tramite uno switch - l' implementazione attuale è figlia di un "rimprovero" di fek e del "paradigm shift" che ne seguì e che mi vide ripassare i vari design pattern, scegliere quello più confacente e scrivere le action seguendolo pedissequamente - per forza è un Command da manuale :D
ma, come all' epoca fece anotare anche fek (che poi rifattorizzò il package del menu aggiungendo le MenuItem), quello sarebbe stato codice C, non Java... e come mi resi subito conto, rispetto al resto del codice di DC o quantomeno rispetto allo stile che il progetto si voleva dare, sarebbe stato un pugno in un occhio

per il ruolo che aveva diamonds questo ha senso e non voglio contestare le vostre scelte

inoltre sarebbe stato meno leggibile e meno manutenibile

questo è un punto di vista, perchè comunque la struttura è ben complessa

correzione: che implementa MenuAction, è un' interfaccia (quindi non c'è nulla di cui dover tenere conto per quanto riguarda eventuali comportamenti definiti nella superclasse e quindi ovverriden nella nuova - basta sapere di dover creare una MenuAction concreta) ;)
hai fatto bene a correggermi (infatti come puoi notare in un mio post precedente avevo usato il verbo "implementare" ;) )

non sto qui a quotare tutto.. comunque le modifiche da apportare a MenuItem non sono da meno rispetto a quelle che avrei fatto io su MainMenu. il resto penso che siano scelte implementative, se vuoi posso anche riscriverti tutta la classe come l'avrei fatta io, ma non mi sembra il caso di imbarcarsi in discorsi su chi ce l'ha più lungo :D
sono scelte IMHO

^TiGeRShArK^
16-09-2007, 22:33
ma cambiare il titolo al thread tipo? :asd:
chèssò..
un "Programmazione di tutto di +" :O
o qualcosa del genere :asd:

PGI-Bis
16-09-2007, 22:40
Saremo decisamente off-topic quando interverrà qualcuno dicendo "a proposito, ma chi è 'sto Torvalds?"

Dott.Wisem
17-09-2007, 00:43
Mi è parso di capire che a Torvalds non piaccia molto il C++. :D
Relativamente al suo modo di esprimersi, credo dipenda dagli ettolitri di birra che si sarà sparato in corpo, prima di rispondere a qualcuno che ha osato criticare la sua ultima creatura. :p

Comunque un po' lo capisco: il C++, fra i linguaggi Object Oriented, non è certo quello più semplice e leggibile... Però è certamente uno dei più efficienti e flessibili.
Mi trovo d'accordo con lui quando dice che per progetti in cui non sono fondamentali le prestazioni, conviene usare un linguaggio molto più high-level del C++ (anche se Torvalds dice che, nel caso in cui servano le prestazioni, conviene usare il C. Di conseguenza, il C++ sarebbe da scartare a prescindere...).

cdimauro
17-09-2007, 07:42
E' una divertente coincidenza. Parliamo di leggibilità e assistiamo ad un caso in cui la conoscenza della lingua non è condizione sufficiente all'acquisizione del significato.
Già. :)

D'altra parte i bug non saltano fuori per una semplice questione di sintassi errata (a questi ci pensa il compilatore). :p

cdimauro
17-09-2007, 07:44
per intenderci... Torvalds non è uno sprovveduto, programmare qualcosa come GIT nel tempo che ci ha messo lui non è da tutti. che poi si possa contestare in tutti i modi il come, il dove e il quando ok, ma lui l'ha fatto e il risultato è di tutto rispetto.
Infatti ci siamo limitati a contestare le sue dichiarazioni. :D

Su GIT, come già detto prima, non conoscendolo preferisco non esprimermi. ;)

cdimauro
17-09-2007, 07:48
Ovviamente mi riferivo ai casi in cui lo si vuole fare :p , e nel tuo caso e' pure piuttosto difficile parlare di copia-incolla. Un esempio abbastanza e' la gestione dei test. Con gli unit test di python dovrei ogni volta che creo una classe di test dovrei crearmi una suite sempre allo stesso modo e aggiungere tale suite all'elenco di quelle create etc., forse non proprio un copia e incolla, ma di una ripetizione mortale. Pero' posso scrivermi un modulo che vada lui in cerca di tutti i file di test, crei automaticamente le suite e le esegua... qualcosa come il seguente:

import unittest
import os
import re
import sys

testRegex = re.compile("test_.*?\.py$")

if len(sys.argv) == 2:
testModules = "test_" + sys.argv[1]
print "Testing",sys.argv[1]
else:
testModules = [ m[:-3] for m in os.listdir(".") if testRegex.match(m) ]
print "Testing", ', '.join(testModules)

def testClasses( moduleName ):
mo = __import__(moduleName)
return [ value for (name,value) in mo.__dict__.items() if name[:4] == "Test" ]


suites = []
for m in testModules:
classSuites = [ unittest.makeSuite(cl) for cl in testClasses(m) ]
suites.append(unittest.TestSuite( classSuites ))

if __name__ == "__main__":
runner = unittest.TextTestRunner()
runner.run( unittest.TestSuite(suites) )

Per progetti non troppo grandi e' tutto quel che serve per aggiungere test senza doverli pure gestire: aggiungi test_qualcosa.py in test/, crei i test in una classe che finisca in Test e sei a posto.
In C++ non lo posso ovviamente fare a meno di ricorrere ad un tool esterno. Era a questo tipo d'uso a cui mi riferivo prima.
OK, è chiaro, e condivido.
Praticamente è quello che fanno tool come Ant e JUnit con Eclipse. :p

P.S. Prima o poi dovrò farmi del male e imparare a usare le espressioni regolari. :(

cdimauro
17-09-2007, 07:51
Il tipo var è stato introdotto per supportare LINQ che è una nuova funzionalità del linguaggio versione 3. Siccome non puoi sapere in anticipo cosa stai trattando (?) allora usi var, ma una volta inizializzata, la variabile è fortemente tipizzata.
Se sto eseguendo una query su un array di stringhe so che il risultato è un array di stringhe, se lo eseguo su una lista di automobili so che il risultato è una lista di automobili.
Quando però ti trovi in mezzo al codice per capire di che tipo è un oggetto var sei costretto ad usare l'intellisense e dedurre il tipo dai metodi che ti vengono propinati, oppure in alternativa andare a studiare il codice per capire che cavolo è, quando si parla di leggibilità...

Ci devono sicuramente essere delle motivazioni più valide alla sua introduzione ma sinceramente mi sfuggono.
Praticamente è una sorta di tipo Variant di VisualBasic, Delphi, ecc.

Lo trovo molto utile, anche se non mi permette di avere dei tipi del tutto "amorfi" (quando li uso con Python for Delphi ho delle limitazioni; ad esempio non posso chiamare un oggetto Variant come se fosse una funzione né posso indicizzarlo).

cdimauro
17-09-2007, 07:57
In relazione alla storia dello switch, mi pare assurdo che al giorno d'oggi un programmatore debba preoccuparsi di usare un costrutto piuttosto che un altro, perché per uno dei due il compilatore genera un codice migliore. Io mi aspetto che sia il compilatore a fare tutte le ottimizzazioni del caso, mentre io programmatore dovrei pensare ai miei algoritmi da un punto di vista prettamente concettuale, non dal punto di vista del modo in cui un certo compilatore genera il codice, altrimenti verrebbe parzialmente meno l'utilità di usare un linguaggio ad alto livello. Certo, mi rendo conto che non esiste il compilatore perfetto.
Se esiste già una soluzione migliore (e tu stesso affermi che come programmatore ti devi occupare soltanto degli algoritmi), è meglio usarla fin da subito, piuttosto che affidarsi ciecamente a un compilatore.

E se dovesse capitare di portare il progetto su un'altra piattaforma e il compilatore non fosse altrettanto efficiente? Capita, e non di rado, proprio perché, come dici tu, non esiste il compilatore perfetto.

cdimauro
17-09-2007, 08:07
E infatti io ho parlato di espressioni complesse nel mio post precedente.
Vammi a mappare la condizione (a < b and c != d) e vediamo se poi è più leggibile di un IF THEN ELSE ... Ammesso che tu ci riesca a farne il mapping! :p

E comunque, anche in una situazione di confronto d'uguaglianza, trovo che il mapping sia meno leggibile. Ad esempio:

switch(c)
{
case 0:
// ...fa qualcosa...
break;
case 1:
// ...fa qualcosa...
break;
case 3:
// ...fa qualcosa...
break;
}

In questo codice riesco a capire immediatamente le condizioni e il comportamento del programma in base al verificarsi di esse.

Invece, in questo:

mappa.get(c).esegui();

onestamente ci capisco poco se non sono stato io a scrivere il programma o se non ho mai visto né usato tecniche di mapping in sostituzione dello switch.
Poi c'è da considerare che, per capire cosa fa il programma, devo andare a vedere come è fatta la funzione di mapping, scorrendo nel codice fino a trovare la funzione apposita. Non sempre sinteticità implica maggiore leggibilità. ;)
def StrToInt(s):
Bases = (('%', 2), ('&', 8), ('$', 16), ('0x', 16), ('0X', 16), ('', 10))
return int(*((s[len(Prefix) : ], Base) for Prefix, Base in Bases if s.startswith(Prefix)).next())
Secondo te questo codice è poco leggibile (da premettere che ho appositamente rimosso la docstring che ne spiega il funzionamento :D)?

Fino a un paio di settimane fa ero composto da una dozzina di righe con una catena di if. ;)

Inutile dire che posso aggiungere altri prefissi senza andare a toccare la riga che esegue il calcolo vero e proprio (es: per introdurre gli ottali col prefisso '0', è sufficiente inserire ('0', 8) prima dell'ultima tupla. ;)).

P.S. Ovviamente non mi aspetto che sia immediatamente comprensibile il suo funzionamento, perché fa uso (particolare :D) di un generatore, della gestione di slice di stringhe, dello spacchettamento di liste/tuple e del funzionamento della funzione/costruttore int() di Python. Quindi bisogna conoscere questo linguaggio, e non in maniera superficiale. :p

cdimauro
17-09-2007, 08:13
Nell'esempio di sopra non credo proprio. :p
E comunque la Complessità Ciclomatica è solo un parametro 'indicativo' della complessità di un codice. Si basa soprattutto sulla considerazione che gran parte dei programmi sono pieni zeppi di strutture di controllo. Ovviamente, se usi il mapping, stai semplicemente 'nascondendo' altrove la complessità del codice.
Al contrario: il codice è semplificato dal fatto che c'è un solo posto in cui viene effettuata la scelta. ;)

cdimauro
17-09-2007, 08:19
Orribile nemmeno tanto... In C la usavo spesso. Aiuta a diminuire la duplicazione del codice.
Per quello è sufficiente definire delle funzioni col codice comune.

Quella di non usare implicitamente un break alla fine del blocco di istruzioni di una ben precisa scelta la trovo una pessima scelta di design del linguaggio.
Le performance devono essere l'ultima causa di scelta di uno o dell'altro costrutto, lo scopo primario deve essere la manutenibilità e la leggibilità.
Ed è più leggibile il codice di uno switch che "trasborda" in quello della successiva scelta? ;)

cdimauro
17-09-2007, 08:21
ma il problema non è nello switch in se, ma nel break. in questo caso lo rilevi con il test solo se le due azioni interferiscono (e comunque di solito interferiscono). dimenticare il break è come dimenticare di chiudere una parentesi
Altro errore che capita con C et similia, ed è impossibile che succeda con altri linguaggi. :D

cdimauro
17-09-2007, 08:26
a parte che anche utilizzando il mapping (il fatto che sia un pattern come dici è marginale) devi modificare la classe MenuItem che poveretta non c'entrava niente.
ma il punto principale è che quando uno dice che le catene di if-else if sono dannose a priori commette un errore (e questo sì che lo stabilisco a priori :D )
l'unica parola che conosco io è: dipende
e aggiungo anche "no silver bullet" (prova a darci un'occhiata su gugol ;) )
No, non dipende: è. :D

Prova a chiedere alla pipeline di un moderno processore out-of-order se una catena if-else è dannosa, e vedi un po' cosa ti risponde. :p

cdimauro
17-09-2007, 08:29
per il ruolo che aveva diamonds questo ha senso e non voglio contestare le vostre scelte

questo è un punto di vista, perchè comunque la struttura è ben complessa

hai fatto bene a correggermi (infatti come puoi notare in un mio post precedente avevo usato il verbo "implementare" ;) )

non sto qui a quotare tutto.. comunque le modifiche da apportare a MenuItem non sono da meno rispetto a quelle che avrei fatto io su MainMenu. il resto penso che siano scelte implementative, se vuoi posso anche riscriverti tutta la classe come l'avrei fatta io, ma non mi sembra il caso di imbarcarsi in discorsi su chi ce l'ha più lungo :D
sono scelte IMHO
Le modifiche sono ben diverse però: un conto è aggiungere una classe e NON toccare di una virgola il codice di selezione del menù, e tutt'altra cosa è aggiungere una condizione di uno switch, che ti costringe e metter mano al codice principale. ;)

cdimauro
17-09-2007, 08:33
Mi è parso di capire che a Torvalds non piaccia molto il C++. :D
Relativamente al suo modo di esprimersi, credo dipenda dagli ettolitri di birra che si sarà sparato in corpo, prima di rispondere a qualcuno che ha osato criticare la sua ultima creatura. :p
E' probabile (vedi immagini che si trovano in giro :asd:), ma il problema non è che a Torvalds non piaccia il C++: è che proprio non l'ha imparato. :asd:
Comunque un po' lo capisco: il C++, fra i linguaggi Object Oriented, non è certo quello più semplice e leggibile... Però è certamente uno dei più efficienti e flessibili.
Mi trovo d'accordo con lui quando dice che per progetti in cui non sono fondamentali le prestazioni, conviene usare un linguaggio molto più high-level del C++ (anche se Torvalds dice che, nel caso in cui servano le prestazioni, conviene usare il C. Di conseguenza, il C++ sarebbe da scartare a prescindere...).
Peccato che il C++ sia tanto efficiente quanto il C con codice che non fa uso di particolari caratteristiche del C++, ed essendo quest'ultimo un superset del C, il linguaggio da scartare a priori sarebbe il C. ;)

cionci
17-09-2007, 08:40
Ed è più leggibile il codice di uno switch che "trasborda" in quello della successiva scelta? ;)
Teoricamente sì...non è tanto diverso dalle etichette a cui ci eravamo abituati con l'assembler. Per chi è abituato a questo genere di cose imho è leggibile.
Contando che di fatto si può fare anche con i mapping.

Guarda un caso del genere allora, immaginati che i nomi delle funzioni siano in realtà autoesplicativi:

case 1:
f1();
f2():
f3();
f4();
break;
case 2:
f2():
f3();
f4();
break;

Ora guarda quest'altro:

case 1:
f1();
case 2:
f2():
f3();
f4();
break;

Non so te, ma Io lo vedo perfettamente leggibile...forse perché ci sono abituato :boh:

cionci
17-09-2007, 08:49
Peccato che il C++ sia tanto efficiente quanto il C con codice che non fa uso di particolari caratteristiche del C++, ed essendo quest'ultimo un superset del C, il linguaggio da scartare a priori sarebbe il C. ;)
Secondo me invece se vedi così il C++ ha fatto bene a scegliere il C. E' probabilmente per questa sua disuniformità che il C++ è difficilmente gestibile in un grande progetto.
Per fare in modo che C++ dia i suoi frutti in un grosso progetto imho bisogna prima di tutto scordarsi dell'esistenza di tutta la libreria standard del C. Inoltre bisogna programmarci solo ed esclusivamente con un approccio object oriented.
Il problema è il "solo ed esclusivamente"...visto che il C++ non ti obbliga a farlo e quindi ci vorrebbero a continue revisioni del codice (in un progetto open source sarebbero in molti a metterci le mani).

Sarebbe bellissimo scrivere un preprocessore del C++ che non ti permette di usare gli include della libreria standard del C e che non ti permette di scrivere funzioni, ma solo classi :sofico:

Dott.Wisem
17-09-2007, 08:52
Se esiste già una soluzione migliore (e tu stesso affermi che come programmatore ti devi occupare soltanto degli algoritmi), è meglio usarla fin da subito, piuttosto che affidarsi ciecamente a un compilatore.
Ti rispondo con la famosa frase: "premature optimization is the root of all evil" (di Tony Hoare e David Knuth) :D.
Comunque dipende sempre dalle situazioni. Se sto scrivendo una routine che già so essere critica a livello di performance della mia applicazione, allora è meglio applicare fin da subito tutte le ottimizzazioni che conosco.
E se dovesse capitare di portare il progetto su un'altra piattaforma e il compilatore non fosse altrettanto efficiente? Capita, e non di rado, proprio perché, come dici tu, non esiste il compilatore perfetto.Dai, non farmi ripetere sempre le stesse cose... Se le performance non sono fondamentali, preferisco 1000 volte scrivere codice meno efficiente, ma più comprensibile e manutenibile. Ritornando alla citazione di prima, è inutile perdere tempo a cercare di ottimizzare del codice che non sarà mai il collo di bottiglia della mia applicazione... Secondo me, il buon designer dovrebbe individuare, in fase di progettazione, quegli elementi del sistema che potrebbero rappresentare dei seri colli di bottiglia e, in fase di implementazione, impegnarsi per ottimizzare solo quelli. Ottimizzare significa quasi sempre perdere di leggibilità.

k0nt3
17-09-2007, 09:18
Infatti ci siamo limitati a contestare le sue dichiarazioni. :D

Su GIT, come già detto prima, non conoscendolo preferisco non esprimermi. ;)
no
è stato detto che non è niente di che come programmatore e addirittura è stato paragonato a gates :asd:

Altro errore che capita con C et similia, ed è impossibile che succeda con altri linguaggi.
no perchè se non chiudi una parentesi te lo dice il compilatore.

No, non dipende: è.

Prova a chiedere alla pipeline di un moderno processore out-of-order se una catena if-else è dannosa, e vedi un po' cosa ti risponde.
come risposta la trovo oltremodo fuori luogo :O a me della pipeline non me può fregare di meno (vale anche la risposta di Wisem) soprattutto se programmo a oggetti

Le modifiche sono ben diverse però: un conto è aggiungere una classe e NON toccare di una virgola il codice di selezione del menù, e tutt'altra cosa è aggiungere una condizione di uno switch, che ti costringe e metter mano al codice principale.

ho già detto prima che comunque per aggiungere una voce al menu bisogna mettere mano al codice di MenuItem oltre a creare una classe che implementa MenuAction.
ora... o io sono cieco oppure modificare MainMenu richiede uno sforzo minore.
se mi dici che per design MainMenu non ha questo compito, allora ti dico che si può cambiare il design. ma ripeto quello che ho detto prima.. sono scelte, io non ti contesto il mapping e tu non contestarmi le catene if-else if

ps. Prova a chiedere alla pipeline di un moderno processore out-of-order se la creazione di tutte quelle classi per implementare il mapping è dannosa e vedi un pò cosa ti risponde

cdimauro
17-09-2007, 09:27
Teoricamente sì...non è tanto diverso dalle etichette a cui ci eravamo abituati con l'assembler. Per chi è abituato a questo genere di cose imho è leggibile.
Contando che di fatto si può fare anche con i mapping.

Guarda un caso del genere allora, immaginati che i nomi delle funzioni siano in realtà autoesplicativi:

case 1:
f1();
f2():
f3();
f4();
break;
case 2:
f2():
f3();
f4();
break;

Ora guarda quest'altro:

case 1:
f1();
case 2:
f2():
f3();
f4();
break;

Non so te, ma Io lo vedo perfettamente leggibile...forse perché ci sono abituato :boh:
Concordo: è una mentalità da programmatori assembly. :D

k0nt3
17-09-2007, 09:29
Concordo: è una mentalità da programmatori assembly. :D
è questione di linguaggio, non di mentalità. allo stesso modo se ti parlo in tedesco probabilmente non mi capisci :D

cdimauro
17-09-2007, 09:31
Secondo me invece se vedi così il C++ ha fatto bene a scegliere il C. E' probabilmente per questa sua disuniformità che il C++ è difficilmente gestibile in un grande progetto.
Per fare in modo che C++ dia i suoi frutti in un grosso progetto imho bisogna prima di tutto scordarsi dell'esistenza di tutta la libreria standard del C. Inoltre bisogna programmarci solo ed esclusivamente con un approccio object oriented.
Il problema è il "solo ed esclusivamente"...visto che il C++ non ti obbliga a farlo e quindi ci vorrebbero a continue revisioni del codice (in un progetto open source sarebbero in molti a metterci le mani).

Sarebbe bellissimo scrivere un preprocessore del C++ che non ti permette di usare gli include della libreria standard del C e che non ti permette di scrivere funzioni, ma solo classi :sofico:
C++ non è il solo linguaggio che offre diversi costrutti per poter programmare.

Per me è a dir poco ovvio che per sviluppare grandi progetti bisogna che tutti tengano conto di alcune linee guida comuni. Perfino Torvalds ne ha scritte alcune.

Col C++ è la stessa cosa: serve gente che conosca BENE il linguaggio e che segua le linee guide che sono state decise. Non ci trovo nulla di particolare / speciale.

cdimauro
17-09-2007, 09:33
Ti rispondo con la famosa frase: "premature optimization is the root of all evil" (di Tony Hoare e David Knuth) :D.
Migliore <> ottimizzato. ;)
Comunque dipende sempre dalle situazioni. Se sto scrivendo una routine che già so essere critica a livello di performance della mia applicazione, allora è meglio applicare fin da subito tutte le ottimizzazioni che conosco.Dai, non farmi ripetere sempre le stesse cose... Se le performance non sono fondamentali, preferisco 1000 volte scrivere codice meno efficiente, ma più comprensibile e manutenibile. Ritornando alla citazione di prima, è inutile perdere tempo a cercare di ottimizzare del codice che non sarà mai il collo di bottiglia della mia applicazione... Secondo me, il buon designer dovrebbe individuare, in fase di progettazione, quegli elementi del sistema che potrebbero rappresentare dei seri colli di bottiglia e, in fase di implementazione, impegnarsi per ottimizzare solo quelli. Ottimizzare significa quasi sempre perdere di leggibilità.
Infatti un codice che fa uso di mapping è migliore perché più facilmente manutenibile. Normalmente lo trovo anche più leggibile.

Dott.Wisem
17-09-2007, 09:34
def StrToInt(s):
Bases = (('%', 2), ('&', 8), ('$', 16), ('0x', 16), ('0X', 16), ('', 10))
return int(*((s[len(Prefix) : ], Base) for Prefix, Base in Bases if s.startswith(Prefix)).next())
Secondo te questo codice è poco leggibile (da premettere che ho appositamente rimosso la docstring che ne spiega il funzionamento :D)? Fino a un paio di settimane fa ero composto da una dozzina di righe con una catena di if. ;)
No, non è che è poco leggibile... E' proprio il festival dell'illeggibilità! Un ciclo for alla fine di una riga? Una condizione, if s.startswith(Prefix), che, se verificata, determina l'esecuzione dello statement a inizio riga *((s[len(Prefix) : ], Base) ? Ok, sarà molto sintetico, ma per leggerlo devo fare le contorsioni... :D
Ammesso che non conosco il Python, non era molto meglio scrivere una cosa del tipo:

def StrToInt(s):
Bases = (('%', 2), ('&', 8), ('$', 16), ('0x', 16), ('0X', 16), ('', 10))
for (Prefix, Base) in Bases
if (s.startswith(Prefix))
return int( *((s[len(Prefix) : ], Base)) )

?

[...]P.S. Ovviamente non mi aspetto che sia immediatamente comprensibile il suo funzionamento, perché fa uso (particolare :D) di un generatore, della gestione di slice di stringhe, dello spacchettamento di liste/tuple e del funzionamento della funzione/costruttore int() di Python. Quindi bisogna conoscere questo linguaggio, e non in maniera superficiale. :p
Quindi ti sei reso conto tu stesso che la leggibilità e quel pezzo di codice in Python viaggiano su due strade differenti...

cdimauro
17-09-2007, 09:44
no
è stato detto che non è niente di che come programmatore e addirittura è stato paragonato a gates :asd:
Se fa delle dichiarazioni da far ridere i polli è il minimo che si possa aspettare.
no perchè se non chiudi una parentesi te lo dice il compilatore.
Appunto: se ometti il break il compilatore NON te lo dice, mentre in altri linguaggi è impossibile che ciò accada.
come risposta la trovo oltremodo fuori luogo :O a me della pipeline non me può fregare di meno (vale anche la risposta di Wisem) soprattutto se programmo a oggetti
Infatti se programmi a oggetti come si deve le catene degli if-else te le scordi :p, e la pipeline non protesta ma, anzi, apprezza (e ricorda che le architetture moderne si trovano molto bene a eseguire codice con salti incondizionati e a gestire chiamate a subroutine). ;)
ho già detto prima che comunque per aggiungere una voce al menu bisogna mettere mano al codice di MenuItem oltre a creare una classe che implementa MenuAction.
ora... o io sono cieco oppure modificare MainMenu richiede uno sforzo minore.
se mi dici che per design MainMenu non ha questo compito, allora ti dico che si può cambiare il design. ma ripeto quello che ho detto prima.. sono scelte, io non ti contesto il mapping e tu non contestarmi le catene if-else if
Te le contesto perché, ripeto, col mapping non devi andare a toccare il codice principale. Mi sembra banale. Se ti serve definire un altra voce di menù, estendi la classe base da cui derivano tutte per aggiungere un nuovo tassello senza toccare di una virgola tutto il resto.

A me il vantaggio mi sembra evidente.
ps. Prova a chiedere alla pipeline di un moderno processore out-of-order se la creazione di tutte quelle classi per implementare il mapping è dannosa e vedi un pò cosa ti risponde
Risponde che è un'ottima soluzione, visto che al costo della creazione di UNA istanza, il codice che ne fa uso n volte non svuoterà la pipeline n volte a causa delle continue misprediction di una catena if-else. ;)

cdimauro
17-09-2007, 09:46
è questione di linguaggio, non di mentalità. allo stesso modo se ti parlo in tedesco probabilmente non mi capisci :D
E' anche di mentalità: il break nello switch fa il paio con gli operatori ++ e -- che vennero aggiunti da K & R per permettere di sfruttare le modalità di indirizzamento del processore PDP su cui doveva girare la prima versione di Unix...

cdimauro
17-09-2007, 09:52
No, non è che è poco leggibile... E' proprio il festival dell'illeggibilità! Un ciclo for alla fine di una riga? Una condizione, if s.startswith(Prefix), che, se verificata, determina l'esecuzione dello statement a inizio riga *((s[len(Prefix) : ], Base) ? Ok, sarà molto sintetico, ma per leggerlo devo fare le contorsioni... :D
No, bisogna semplicemente imparare a usare le generator expression di Python: http://www.python.org/dev/peps/pep-0289/ ;)
Ammesso che non conosco il Python, non era molto meglio scrivere una cosa del tipo:

def StrToInt(s):
Bases = (('%', 2), ('&', 8), ('$', 16), ('0x', 16), ('0X', 16), ('', 10))
for (Prefix, Base) in Bases
if (s.startswith(Prefix))
return int( *((s[len(Prefix) : ], Base)) )

?

Quindi ti sei reso conto tu stesso che la leggibilità e quel pezzo di codice in Python viaggiano su due strade differenti...
Dipende da quel che si vuol ottenere: il mio codice non ha lo scopo di far vedere come si impara a programmare in Python, altrimenti avrei usato un codice simile al tuo.

Il mio codice è scritto per chi conosce bene Python (l'avevo anche scritto :D) e per cui una generator expression è facile da leggere. ;)

Dott.Wisem
17-09-2007, 09:54
Al contrario: il codice è semplificato dal fatto che c'è un solo posto in cui viene effettuata la scelta. ;)Si, ma per capire cosa succede devi scorrere il codice andando a vedere quella funzione dove porta... Il ché è comodo se non te ne importa nulla del codice da eseguire in base al verificarsi di una certa condizione. Poi, se le scelte di uno switch sono poche, per me il mapping è meno leggibile.

cdimauro
17-09-2007, 10:01
Si, ma per capire cosa succede devi scorrere il codice andando a vedere quella funzione dove porta...
Certamente.
Il ché è comodo se non te ne importa nulla del codice da eseguire in base al verificarsi di una certa condizione.
Che è quello che si verifica normalmente. :p
Poi, se le scelte di uno switch sono poche, per me il mapping è meno leggibile.
Se sono poche, tanto vale affidarsi a un if-else. ;)

k0nt3
17-09-2007, 10:09
Se fa delle dichiarazioni da far ridere i polli è il minimo che si possa aspettare.
:confused:

Appunto: se ometti il break il compilatore NON te lo dice, mentre in altri linguaggi è impossibile che ciò accada.

in java ad esempio è come in C

Infatti se programmi a oggetti come si deve le catene degli if-else te le scordi :p, e la pipeline non protesta ma, anzi, apprezza (e ricorda che le architetture moderne si trovano molto bene a eseguire codice con salti incondizionati e a gestire chiamate a subroutine). ;)

se programmi a oggetti come si deve la pipeline non la nomini nemmeno

Te le contesto perché, ripeto, col mapping non devi andare a toccare il codice principale. Mi sembra banale. Se ti serve definire un altra voce di menù, estendi la classe base da cui derivano tutte per aggiungere un nuovo tassello senza toccare di una virgola tutto il resto.

A me il vantaggio mi sembra evidente.

a me no perchè ti ripeto per l'ultima volta che con il mapping bisogna pur sempre modificare la classe MenuItem

Risponde che è un'ottima soluzione, visto che al costo della creazione di UNA istanza, il codice che ne fa uso n volte non svuoterà la pipeline n volte a causa delle continue misprediction di una catena if-else. ;)
certo al costo di chiamare un metodo che chiama un metodo che chiama un metodo..

k0nt3
17-09-2007, 10:11
Il mio codice è scritto per chi conosce bene Python (l'avevo anche scritto :D) e per cui una generator expression è facile da leggere. ;)
il tuo codice è tutto quello che vuoi ma di certo non è facile da leggere

Dott.Wisem
17-09-2007, 10:16
No, bisogna semplicemente imparare a usare le generator expression di Python: http://www.python.org/dev/peps/pep-0289/ ;)

Dipende da quel che si vuol ottenere: il mio codice non ha lo scopo di far vedere come si impara a programmare in Python, altrimenti avrei usato un codice simile al tuo.La versione che ho scritto io (che non ho idea se sia sintatticamente corretta per il Python) determina una diminuzione della difficoltà di lettura di un fattore 10x anche per chi non sia un "perfetto" conoscitore dei meccanismi di quel linguaggio. Ciò si traduce in un notevole aumento di leggibilità (visto che riesco a farmi capire anche da chi non conosce il particolare linguaggio usato). Ma io credo che anche chi lo conosce possa trarne notevoli benefici, essendo più in linea con le usuali convenzioni del 99% degli altri linguaggi (quindi non devi fare troppi sforzi mentali per disabituarti ad una convenzione ed abituarti ad un'altra).

Secondo te, è più leggibile:

Print(i) for i=1 to 10 if i%2 is 0

oppure:

for i=1 to 10
{
if i%2 is 0
Print(i)
}

?


Il mio codice è scritto per chi conosce bene Python (l'avevo anche scritto :D) e per cui una generator expression è facile da leggere. ;)
Ma allora non avresti dovuto proporlo come esempio di leggibilità...

cdimauro
17-09-2007, 10:28
:confused:
Ribadisco: abbiamo contestato le sue dichiarazioni e mostrato che non è un granché come programmatore.
in java ad esempio è come in C
Chi l'ha mai negato? Ho sempre parlato di linguaggi C-like. :p
se programmi a oggetti come si deve la pipeline non la nomini nemmeno
Perché non n'è nemmeno bisogno. ;)
a me no perchè ti ripeto per l'ultima volta che con il mapping bisogna pur sempre modificare la classe MenuItem
Certamente, ma devi crearti soltanto l'istanza di una classe.
certo al costo di chiamare un metodo che chiama un metodo che chiama un metodo..
Che è MOLTO MENO COSTOSO che far svuotare una pipeline ogni 3 x 2.
il tuo codice è tutto quello che vuoi ma di certo non è facile da leggere
Rileggendolo l'unica cosa che potrei fare se volessi renderlo più leggibile è mettere la generator expression in una variabile:
def StrToInt(s):
Bases = (('%', 2), ('&', 8), ('$', 16), ('0x', 16), ('0X', 16), ('', 10))
Choise = (s[len(Prefix) : ], Base) for Prefix, Base in Bases if s.startswith(Prefix)).next())
return int(*Choise)
Questo giusto per esplicitare qual è il suo output, ma la generator expression di per sé mi sembra leggibile:

"ritorna una coppia formata dalla stringa risultante da s (togliendo il prefisso) e dalla base, prendendo prefisso e base dalle basi per cui si verifica che la stringa abbia quel prefisso".

Il next() ritorna soltanto la prima coppia che soddisfa la condizione. Questo perché startswith ritorna sempre True se Prefix è uguale alla stringa vuota, quindi è una sorta di "ancora di salvezza" nel caso in cui non fosse rilevata la presenza di un prefisso fra quelli riconosciuti (per questo ho inserito ('', 10) alla fine: per male che vada la base da usare sarà quella decimale).

k0nt3
17-09-2007, 10:40
Ribadisco: abbiamo contestato le sue dichiarazioni e mostrato che non è un granché come programmatore.

mi sono perso la parte in cui è stato mostrato qualcosa.. me la puoi linkare? :fagiano:

Chi l'ha mai negato? Ho sempre parlato di linguaggi C-like. :p

no stavi parlando di C :p

Perché non n'è nemmeno bisogno. ;)

non capisco il nesso con quello che mi hai quotato..

Certamente, ma devi crearti soltanto l'istanza di una classe.

cambia qualcosa?

Che è MOLTO MENO COSTOSO che far svuotare una pipeline ogni 3 x 2.

spetta al compilatore fare di meglio

Rileggendolo l'unica cosa che potrei fare se volessi renderlo più leggibile è mettere la generator expression in una variabile:
def StrToInt(s):
Bases = (('%', 2), ('&', 8), ('$', 16), ('0x', 16), ('0X', 16), ('', 10))
Choise = (s[len(Prefix) : ], Base) for Prefix, Base in Bases if s.startswith(Prefix)).next())
return int(*Choise)
Questo giusto per esplicitare qual è il suo output, ma la generator expression di per sé mi sembra leggibile:

"ritorna una coppia formata dalla stringa risultante da s (togliendo il prefisso) e dalla base, prendendo prefisso e base dalle basi per cui si verifica che la stringa abbia quel prefisso".

Il next() ritorna soltanto la prima coppia che soddisfa la condizione. Questo perché startswith ritorna sempre True se Prefix è uguale alla stringa vuota, quindi è una sorta di "ancora di salvezza" nel caso in cui non fosse rilevata la presenza di un prefisso fra quelli riconosciuti (per questo ho inserito ('', 10) alla fine: per male che vada la base da usare sarà quella decimale).
perl in confronto è autoesplicativo :asd:

cdimauro
17-09-2007, 10:46
La versione che ho scritto io (che non ho idea se sia sintatticamente corretta per il Python)
No, non lo era ma ovviamente non m'interessava la sua correttezza formale, ma il concetto che volevi esprimere. :)
determina una diminuzione della difficoltà di lettura di un fattore 10x anche per chi non sia un "perfetto" conoscitore dei meccanismi di quel linguaggio. Ciò si traduce in un notevole aumento di leggibilità (visto che riesco a farmi capire anche da chi non conosce il particolare linguaggio usato).
Indubbiamente: chi non conosce Python e certi costrutti si può trovare spiazzato. In genere è quel che capita quando ci si trova davanti una list comprehension o una generator expression (che sono MOLTO simili: sintatticamente sono identiche, a parte l'uso delle parentesi quadre al posto delle tonde nel primo caso per racchiudere l'espressione "generatrice").
Ma io credo che anche chi lo conosce possa trarne notevoli benefici, essendo più in linea con le usuali convenzioni del 99% degli altri linguaggi (quindi non devi fare troppi sforzi mentali per disabituarti ad una convenzione ed abituarti ad un'altra).
No, da chi conosce Python non mi aspetto una difficoltà di lettura. Tutt'altro.

Poi onestamente di come funzionano le cose con gli altri linguaggi m'interessa ben poco: quando programmo con un preciso linguaggio non voglio e non devo farmi condizionare dagli schemi mentali a cui ero abituato.

Cosa che capita, ad esempio, quando uno che è abituato alla programmazione procedurale comincia a lavorare con la programmazione a oggetti: nei primi tempi il codice che scriverà sarà tutto fuorché "secondo i canoni della OOP", usando per lo più l'incapsulamento di codice e dati (pratica molto comune in linguaggi come PHP, che non hanno il concetto di modulo / package).
Secondo te, è più leggibile:

Print(i) for i=1 to 10 if i%2 is 0

oppure:

for i=1 to 10
{
if i%2 is 0
Print(i)
}

?
La prima, nettamente: ho già immediatamente visibile ciò che otterò, e a seguire COME lo otterò (che è meno interessante).
Ma allora non avresti dovuto proporlo come esempio di leggibilità...
In questo caso in effetti ho sbagliato perché ho mischiato un esempio d'uso di una mappa al posto di uno switch, con un costrutto più leggibile.

Avrei dovuto usare questo:
Resolver = {
'PDU:' : lambda URI, Parameters: URI,
'http:' : httpResolver,
'https:' : httpsResolver,
'db:' : lambda URI, Parameters: GetData(DBUtils.SQLGet, URI, Parameters)
}


def ResolveURI(URI, Parameters):
if URI:
Index = URI.find(':', 0, 10)
if Index >= 0:
Index = Index + 1
Prefix = URI[ : Index]
URI = URI[Index : ]
URI = Resolver[Prefix](URI, Parameters) # Qui si esegue la scelta, tramite map in questo caso, o tramite catena di if-else

return URI

return ''
In questo caso la decisione viene presa in un punto ben preciso del codice (quello che precede return URI), e il significato mi sembra chiaro e leggibile (Resolver è un dizionario / mappa che restituisce una funzione da chiamare).

Speriamo sia la volta buona. :p

The3DProgrammer
17-09-2007, 10:48
se mi dici che per design MainMenu non ha questo compito, allora ti dico che si può cambiare il design. ma ripeto quello che ho detto prima.. sono scelte, io non ti contesto il mapping e tu non contestarmi le catene if-else if



ma lol, non è che qui si vuole contestare te o le tue scelte, ognuno fa come meglio crede...il problema è che noi ti stiamo dando delle motivazioni precise e rilevanti sul perchè la catena di if, SOPRATTUTTO nel contesto prima descritto (cioè un modulo software che deve realizzare una funzionalità ad alta suscettibilità di modifiche future quali un menu) non è adatta. Un principio "abbastanza" importante violato da quel codice è stato già descritto, se vuoi possono citartene almeno un altro (il principio di singola responsabilità: andando a inserire tutto il codice di gestione dei menu items in quella catena di if tu dai al gestore del menu + responsabilità, quindi + possibilità di fare errori in quel modulo, quindi + possibilità di doverlo modificare per compiti che non gli spettano).



a me no perchè ti ripeto per l'ultima volta che con il mapping bisogna pur sempre modificare la classe MenuItem

Come detto non conosco il codice, ma evidentemente non rispetta al 100% il principio open/closed (se lo rispettasse questa modifica non sarebbe necessaria).


no silver bullet

innanzitutto ti ringrazio per avermi segnalato questo documento interessante. Posso assicurarti che una catena di if come quella descritta sopra aumenta la complessità accidentale: astraiti per un attimo da quel particolare codice, pensa ad un progetto enorme in cui sono necessari 8-10 gestori di menu (ognuno contenenti voci diverse), e supponi che dopo aver completato il tutto devi ancora inserire lo stesso menuItem (che so, exit) in tutti quanti: cosa succede nel tuo caso ed in quello scritto in diamonds?

cdimauro
17-09-2007, 10:59
mi sono perso la parte in cui è stato mostrato qualcosa.. me la puoi linkare? :fagiano:
Devi partire dall'inizio del thread. :D
no stavi parlando di C :p
In quel caso sì, perché era di questo linguaggio che si stava parlando, ma in altre occasioni quando parlavo di sintassi dei linguaggi puoi notare che mi sono riferito spesso a quelli "C-like", "derivati del C", ecc. ;)

Mi sembra scontato che se dico che c'è un errore nel design del linguaggio, e ci sono altri linguaggi che fanno la stessa scelta, il mio parere varrà anche in questo caso.

Se c'è bisogno che lo ripeta ogni volta "per non fare discriminazioni", basta dirlo, ma mi sembrava normale. ;)
non capisco il nesso con quello che mi hai quotato..
Perché programmando opportunamente a oggetti è normale rimuovere dei salti condizionati, che sono una delle più grandi piaghe delle pipeline.
cambia qualcosa?
Scherzi? Una sola volta all'inizio del codice crei un'istanza per ogni oggetto che ti serve, dopodiché se nel codice la CPU passerà n volte da quel pezzo di codice interessato, effettuarà soltanto una chiamata a quel metodo e senza mai svuotare la pipeline (a meno che non ci sia una page miss, ma lasciamo da parte i casi dovuti alla sfiga e che, comunque, possono colpire qualunque tipo di codice :p).

Viceversa, con una catena di if-else, le n volte che ci passerà dovrà eseguire (mediamente) m / 2 confronti e relativi salti condizionati, con conseguente svuotamento delle pipeline.

Non c'è proprio paragone in termini di efficienza.
spetta al compilatore fare di meglio
Non ne puoi essere sicuro. Una soluzione algoritmica, invece, ti metterà SEMPRE al riparo a prescindere dalla bontà del compilatore.

Questo senza considerare la maggior manutenibilità (e per me anche leggibilità) del codice, che è un valore aggiunto non indifferentente. ;)
perl in confronto è autoesplicativo :asd:
PERL non lo capisce nemmeno chi l'ha creato. :asd:

http://www.tyborg.com/2005/10/05/a-programmers-strength-flows-from-code-maintainability/

:p

marco.r
17-09-2007, 11:16
Ribadisco la mia opinione: la differenza essenziale che io vedo tra lo switch e la mappa sta nel fatto che mentre lo switch esprime l'atto e il procedimento decisionale, la mappa si limita al primo elemento.

La mappa dice solamente che è presa una decisione. Come questa decisione sia presa è espresso da un'altra parte.

Io aggiungerei un altro paio di differenze.
Quella che secondo me è ancor piu' fondamentale e' che lo switch e' codice mentre la mappa e' dati. In un linguaggio come il C++ dove il codice e' statico e poco manipolabile la mappa da alcuni vantaggi non banali.
In primis la posso passare come argomento, per cui io posso (ad esempio) gestire diversi menu con lo stesso codice (questo per certi si riallaccia a quanto hai appena detto tu).
Lo posso modificare a runtime (togliere e rimuovere menu).
Meglio ancora posso generarla automaticamente, ad esempio il menu dei plugin potrei generarlo a partire dall'elenco dei files presenti in una certa cartella sul file system.
Ovviamente questi sono vantaggi nel momento in cui mi servono... se io ho una enumerazione che per sua stessa natura non cambiera' nel tempo potrebbe essere piu' semplice lo switch, per lo stesso motivo per cui spesso e' piu' complicato, ovvero il fatto che mette assieme "atto e procedimento decisionale", come dici tu.
In realta' non sono molti i casi in cui è piu' semplice lo switch, perchè quest'ultimo in C++ è molto limitato, in particolare prevede solo valori interi...
In Ruby lo switch è piu' potente, permette ad esempio di fare un check su intervalli:

rating = case votesCast
when 0...10 then Rating::SkipThisOne
when 10...50 then Rating::CouldDoBetter
else Rating::Rave
end

Altri linguaggi permettono pure pattern matching o il confronto di piu' valori contemporaneamente

sumFirstTwo list = case list of
[] -> []
[x] -> [x]
(x:y:xs) -> (x+y:xs)

in questi casi lo switch (o case che dir si voglia) diventa un'alternativa decisamente piu' ragionevole

k0nt3
17-09-2007, 11:21
ma lol, non è che qui si vuole contestare te o le tue scelte, ognuno fa come meglio crede...il problema è che noi ti stiamo dando delle motivazioni precise e rilevanti sul perchè la catena di if, SOPRATTUTTO nel contesto prima descritto (cioè un modulo software che deve realizzare una funzionalità ad alta suscettibilità di modifiche future quali un menu) non è adatta. Un principio "abbastanza" importante violato da quel codice è stato già descritto, se vuoi possono citartene almeno un altro (il principio di singola responsabilità: andando a inserire tutto il codice di gestione dei menu items in quella catena di if tu dai al gestore del menu + responsabilità, quindi + possibilità di fare errori in quel modulo, quindi + possibilità di doverlo modificare per compiti che non gli spettano).
premessa: i principi a cui fai riferimento non sono generali, ne tanto meno è possibile valutarli esattamente (capisci che parole come "alta suscettibilità", "più responsabilità", "più possibilità".. insomma non sono facili da valutare)
comunque sia la probabilità di commettere errori non cambia, cambia solo il modo in cui è spalmata nel modulo



Come detto non conosco il codice, ma evidentemente non rispetta al 100% il principio open/closed (se lo rispettasse questa modifica non sarebbe necessaria).
va bene, però effettivamente non so come si sarebbe potuto fare a meno di quella modifica



innanzitutto ti ringrazio per avermi segnalato questo documento interessante. Posso assicurarti che una catena di if come quella descritta sopra aumenta la complessità accidentale: astraiti per un attimo da quel particolare codice, pensa ad un progetto enorme in cui sono necessari 8-10 gestori di menu (ognuno contenenti voci diverse), e supponi che dopo aver completato il tutto devi ancora inserire lo stesso menuItem (che so, exit) in tutti quanti: cosa succede nel tuo caso ed in quello scritto in diamonds?
prego :)
non metto in dubbio che il mapping ha la sua utilità. il fatto è che qui si sta mettendo in dubbio che lo switch (o chi ne fa le veci) ha anche lui la sua utilità

comunque nel mio caso aggiungo un blocco else if uguale agli altri appena sopra, mentre nel caso di diamonds devo creare una nuova classe che implementa MenuAction e poi istanziarla in MenuItem