PDA

View Full Version : [C#] switch annidati


vendettaaaaa
23-12-2012, 18:32
switch(calculatorState) {
case CalculatorState.inputVariablesForCalc:
// First and Second function only
if (inThirdFunction)
return;

switch (operationMode) {
case OperationMode.normalMode:

Compiler error: cannot fallthrough.
Lo so che non si può fare il fallthrough se tra due label c'è del codice, ma sono due switch DIVERSI!!!
Non ditemi che devo cambiare gli switch interni con degli IF, non perchè sarebbe una rottura colossale, ma per principio: SONO VARIABILI DIVERSE! :muro:

Braccop
23-12-2012, 19:20
hai provato a racchiudere il 2° switch dentro a {} ?

vendettaaaaa
23-12-2012, 22:46
hai provato a racchiudere il 2° switch dentro a {} ?
Provato adesso, non va -_________-"

P.S.: ho avuto un'illuminazione: ho cannato io! Il problema non è lì, bensì alla fine dei case: non avevo inserito break nonostante dopo non ci fosse più nulla e finisse non solo lo switch ma anche la funzione!!
I break ci vogliono assolutamente, al contrario che in C++ (sto portando codice C++ in C# infatti)...

wingman87
24-12-2012, 10:38
In realtà il fallthrough è possibile ma va esplicitato con "goto case"
http://msdn.microsoft.com/en-us/library/13940fs2.aspx

vendettaaaaa
24-12-2012, 14:42
In realtà il fallthrough è possibile ma va esplicitato con "goto case"
http://msdn.microsoft.com/en-us/library/13940fs2.aspx
Hmm non avevo mai pensato che il goto può riferirsi alle label di uno switch...interessante! Potrebbe permettermi di "lumpare" un bel po' di righe di codice.
E prima che intervenga qualcuno: non me ne fotte niente se il goto è sconsigliato. Basta starci attenti :)

Vincenzo1968
24-12-2012, 15:32
Ci sono due situazioni in cui il goto è lecito: una è, come nel tuo caso, uscire da cicli e/o switch case annidati; l'altra è per migliorare le prestazioni come spiega Knuth nel suo bell'articolo "Structure Programming with goto Statements".

E se lo consiglia Knuth ci si può fidare ;)

Tratto dall'articolo di cui sopra:


Before beginning a more technical discussion. I should confess that the title of this article was chosen primarily to generate attention.
There are doubtless some readers who are convinced that abolition of go to statements is merely a fad. and they may see this title and think, "Aha! Knuth is rehabilitating the go to statement, and we can go back to our old ways of programming again." Another class of readers will see the heretical title and think, "When are diehards like Knuth going to get with it?" I hope that both classes of people will read on and discover that what I am really doing is striving for a reasonably well balanced viewpoint about the proper role of go to statements. I argue for the elimination of go to's in certain cases, and for their introduction in others.

I believe that by presenting such a view I am not in fact disagreeing sharply with Dijkstra's ideas, since he recently wrote the following: "Please don't fall into the trap of believing that I am terribly dogmatical about [the go to statement].
I have the uncomfortable feeling that others are making a religion out of it, as if the conceptual problems of programming could be solved by a single trick, by a simple form of coding discipline!" [29]. In other words, it, seems that fanatical advocates of the New Programming are going overboard in their strict enforcement of morality and purity in programs.

...

Of course I wouldn't bother making such optimizations on a oneshot job, but when it's a question of preparing quality programs, I don't want to restrict myself to tools that deny me such efficiencies.
There is no doubt that the grail of efficiency leads to abuse. Programmers waste enormous amounts of time thinking about, or worrying about, the speed of noncritical parts of their programs, and these attempts at efficiency actually have a strong negative impact when debugging and maintenance are considered. We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil.

...

Now that I have discussed how to remove go to statements, I will turn around and show why there are occasions when I actually wish to insert them into a go to-less program.
The reason is that I like well-documented programs very much, but I dislike inefficient ones; and there are some cases where I simply seem to need go to statements, despite the examples stated above.

wingman87
24-12-2012, 17:44
Veramente io sono uno di quelli che "aborra" i goto, però in questo caso il "goto case" di goto ha solo il nome, almeno quando lo usi per passare al case successivo. L'intenzione alla base è quella di evitare a compile time dei case che non finiscono con break per dimenticanza: dovendo esplicitare sia il break che il fallthrough è più difficile fare errori di distrazione.

Vincenzo1968
24-12-2012, 18:45
Pure io lo evito(e, a dire il vero, non m'è mai capitato di doverlo usare). Ma, ci sono situazioni in cui può essere utile. Ti consiglio di procurarti una copia dell'articolo di Knuth, è illuminante in proposito(purtroppo non posso postarlo tutto per ovvi motivi di copyright).

Come dice Knuth, amo i programmi ben documentati e ben formati ma non amo affatto quelli inefficienti. Perché privarsi di uno strumento che può notevolmente migliorare l'efficienza? E dove siamo? nel Congo Belga? (Cit. Totò(nel film "I Tartassati")).

WarDuck
24-12-2012, 18:48
Ci sono due situazioni in cui il goto è lecito: una è, come nel tuo caso, uscire da cicli e/o switch case annidati; l'altra è per migliorare le prestazioni come spiega Knuth nel suo bell'articolo "Structure Programming with goto Statements".

E se lo consiglia Knuth ci si può fidare ;)

Tratto dall'articolo di cui sopra:

Aggiungo il terzo, e forse l'unico caso reale in cui può essere utile usare un goto, soprattutto in C: la gestione degli errori e il rilascio delle risorse in seguito ad un errore.

Mettiamo che hai fatto una serie di allocazioni, e si possono verificare più avanti nel codice un paio di errori diversi tra loro, uno non grave, l'altro grave, ma che hanno una serie di parti comuni... in questo caso oltre ad essere utile è consigliabile usare un goto per gestire la parte comune dell'errore.

In questo modo non solo si rende il codice più leggibile ma si evita la replicazione del codice, cosa che potrebbe essere dannosa nel caso in cui si debba effettuare una modifica (ci si può dimenticare di farla in un altro ramo ad esempio).


Questo in C, chiaramente altri linguaggi dispongono di soluzioni ad-hoc, come le eccezioni, per gestire gli errori.

WarDuck
24-12-2012, 18:50
Pure io lo evito(e, a dire il vero, non m'è mai capitato di doverlo usare). Ma, ci sono situazioni in cui può essere utile. Ti consiglio di procurarti una copia dell'articolo di Knuth, è illuminante in proposito(purtroppo non posso postarlo tutto per ovvi motivi di copyright).

Come dice Knuth, amo i programmi ben documentati e ben formati ma non amo affatto quelli inefficienti. Perché privarsi di uno strumento che può notevolmente migliorare l'efficienza? E dove siamo? nel Congo Belga? (Cit. Totò(nel film "I Tartassati")).

Il goto come metodo per incrementare le prestazioni, al giorno d'oggi, è alquanto deboluccia come tesi, specie per via di tutte le ottimizzazioni che fanno i compilatori.

Chiaramente con tutto il rispetto per Knuth, se il tuo programma ha un problema di prestazioni, vai con un profiler e vedi dov'è il problema, e non è detto che sia l'implementazione, potrebbe benissimo essere l'algoritmo utilizzato ad essere inefficiente.

PS: noto ora che l'articolo è del 1974... direi che è il caso di aggiornarsi un po', dubito fortemente che oggi valgano ancora quelle considerazioni.

Vincenzo1968
24-12-2012, 19:17
Aggiungo il terzo, e forse l'unico caso reale in cui può essere utile usare un goto, soprattutto in C: la gestione degli errori e il rilascio delle risorse in seguito ad un errore.

Mettiamo che hai fatto una serie di allocazioni, e si possono verificare più avanti nel codice un paio di errori diversi tra loro, uno non grave, l'altro grave, ma che hanno una serie di parti comuni... in questo caso oltre ad essere utile è consigliabile usare un goto per gestire la parte comune dell'errore.

In questo modo non solo si rende il codice più leggibile ma si evita la replicazione del codice, cosa che potrebbe essere dannosa nel caso in cui si debba effettuare una modifica (ci si può dimenticare di farla in un altro ramo ad esempio).


Questo in C, chiaramente altri linguaggi dispongono di soluzioni ad-hoc, come le eccezioni, per gestire gli errori.

La gestione degli errori è proprio uno dei casi di cui parla Knuth nel seguito del suo articolo.

Vincenzo1968
24-12-2012, 19:23
Il goto come metodo per incrementare le prestazioni, al giorno d'oggi, è alquanto deboluccia come tesi, specie per via di tutte le ottimizzazioni che fanno i compilatori.

Chiaramente con tutto il rispetto per Knuth, se il tuo programma ha un problema di prestazioni, vai con un profiler e vedi dov'è il problema, e non è detto che sia l'implementazione, potrebbe benissimo essere l'algoritmo utilizzato ad essere inefficiente.

PS: noto ora che l'articolo è del 1974... direi che è il caso di aggiornarsi un po', dubito fortemente che oggi valgano ancora quelle considerazioni.

D'accordissimo ma certe situazioni descritte nell'articolo di Knuth sono valide ancora oggi.
Per esempio, il goto ti consente di evitare la ricorsione nel caso in cui ce ne fosse bisogno(per le prestazioni o per evitare di esaurire lo stack di sistema). Naturalmente è possibile eliminare la ricorsione anche senza goto ma a volte il codice si complica un po' troppo. Un esempio è dato nel Sedgewick che illustra come eliminare la ricorsione dall'algoritmo per l'attraversamento degli alberi binari. Sedgewick prosegue poi mostrando com'è possibile eliminare i goto ed avere un algoritmo non ricosivo. Anche se nell'esempio finale il codice non è molto più complicato rispetto alla versione ricorsiva, il ragionamento da fare per arrivarci è lungo e tortuoso.

Vincenzo1968
24-12-2012, 19:55
Il pdf con l'articolo di Knuth:

http://sbel.wisc.edu/Courses/ME964/Literature/knuthProgramming1974.pdf

Vincenzo1968
24-12-2012, 23:39
Altro gran bell'articolo in cui si spiega in quali casi(pochi, pochissimi) è cosa buona e giusta usare il goto:

by Steven C. McConnell
http://www.stevemcconnell.com/ccgoto.htm

Here's a summary of guidelines for using gotos:

Use gotos to emulate structured control constructs in languages that don't support them directly. When you emulate structured constructs, emulate them exactly. Don't abuse the extra flexibility the goto gives you.
Don't use gotos when an equivalent structured construct is available.
Measure the performance of any goto used to improve efficiency. In most cases that use gotos, you can recode them without gotos with improved readability and no loss in efficiency. If your case is the exception, document the efficiency improvement so that gotoless evangelists :D won't remove it when they see it.
Limit yourself to one goto label per routine, unless you're emulating structured constructs.
Limit yourself to gotos that go forward, not backward, unless you're emulating structured constructs.
Make sure all goto labels are used. They might be a symptom of missing code, namely the code that goes to them. If they're not used, delete them.
Make sure a goto doesn't create unreachable code.
If you're a manager, adopt the perspective that a battle over a single goto isn't worth the loss of the war. If the programmer is aware of the alternatives and is willing to argue, the goto is probably OK.

WarDuck
25-12-2012, 10:15
D'accordissimo ma certe situazioni descritte nell'articolo di Knuth sono valide ancora oggi.
Per esempio, il goto ti consente di evitare la ricorsione nel caso in cui ce ne fosse bisogno(per le prestazioni o per evitare di esaurire lo stack di sistema). Naturalmente è possibile eliminare la ricorsione anche senza goto ma a volte il codice si complica un po' troppo. Un esempio è dato nel Sedgewick che illustra come eliminare la ricorsione dall'algoritmo per l'attraversamento degli alberi binari. Sedgewick prosegue poi mostrando com'è possibile eliminare i goto ed avere un algoritmo non ricosivo. Anche se nell'esempio finale il codice non è molto più complicato rispetto alla versione ricorsiva, il ragionamento da fare per arrivarci è lungo e tortuoso.

Rimane un articolo del 1974, e i compilatori ne hanno fatta di strada, quelli più moderni eliminano la tail recursion a compile-time.

L'altro articolo è del 1993.

Ricordo a tutti che siamo all'alba del 2013, per cui già solo un articolo di 5 anni fa può non essere più valido in ambito scientifico, figurarsi uno di 20.

Questo non significa che alcune tesi non siano ancora valide oggi, ma andrebbero dimostrate, specie considerati i progressi nell'ambito dei compilatori.

Vincenzo1968
25-12-2012, 20:11
Rimane un articolo del 1974, e i compilatori ne hanno fatta di strada, quelli più moderni eliminano la tail recursion a compile-time.

L'altro articolo è del 1993.

Ricordo a tutti che siamo all'alba del 2013, per cui già solo un articolo di 5 anni fa può non essere più valido in ambito scientifico, figurarsi uno di 20.

Questo non significa che alcune tesi non siano ancora valide oggi, ma andrebbero dimostrate, specie considerati i progressi nell'ambito dei compilatori.

La tail recursion è facilmente sostituibile con un ciclo while anche a mano. Nel Sedgewich si parla di ricorsione non in coda.

Questo articolo(del 2012) mostra come si può ottenere un incremento di efficienza tramite goto:

http://eli.thegreenplace.net/2012/07/12/computed-goto-for-efficient-dispatch-tables/

Ribadisco comunque che finora, vent'anni che programmo, non m'è mai capitato di dover usare l'istruzione goto. Non sono per l'efficienza a tutti i costi; ma non sono neanche un "gotoless evangelists" :D

Vincenzo1968
25-12-2012, 20:21
Volendo si può usare il goto anche nei linguaggi che non lo prevedono:

Java : http://www.steike.com/code/useless/java-goto/
JavaScript: http://summerofgoto.com/
Python: http://entrian.com/goto/


# Example 1: Breaking out from a deeply nested loop:
from goto import goto, label
for i in range(1, 10):
for j in range(1, 20):
for k in range(1, 30):
print i, j, k
if k == 3:
goto .end
label .end
print "Finished\n"


http://www.hwupgrade.org/public/style_emoticons/default/coolface.png

Vincenzo1968
26-12-2012, 10:44
I sorgenti di Python:

Python 2.7:
http://img826.imageshack.us/img826/3893/python273goto.jpg

Python 3.3:
http://img254.imageshack.us/img254/6051/python333goto01.jpg
http://img267.imageshack.us/img267/8361/python333goto02.jpg

Però è il colmo: considerano il costrutto goto il male assoluto(tant'è che non lo implementano nel linguaggio) ma non si fanno scrupoli nell'utilizzarlo in CPython per aumentare le prestazioni :rolleyes:

:D

Vincenzo1968
26-12-2012, 11:06
http://blogs.mathworks.com/steve/2009/08/27/knuth-on-go-to-1974/

Vincenzo1968
26-12-2012, 18:35
D'altronde cos'è un blocco try/catch se non un goto camuffato, un eufemismo per saltare da qualche parte senza scrivere la parola "goto"?


Other go to-less languages for system programming have similarly introduced other statements which provide "equally powerful" alternative ways to jump. In other words, it seems that there is widespread agreement that go to statements are harmful, yet programmers and language designers still feel the need for some euphemism that "goes to" without saying go to.

Donald E. Knuth

cdimauro
28-12-2012, 11:28
Volendo si può usare il goto anche nei linguaggi che non lo prevedono:

Java : http://www.steike.com/code/useless/java-goto/
JavaScript: http://summerofgoto.com/
Python: http://entrian.com/goto/


# Example 1: Breaking out from a deeply nested loop:
from goto import goto, label
for i in range(1, 10):
for j in range(1, 20):
for k in range(1, 30):
print i, j, k
if k == 3:
goto .end
label .end
print "Finished\n"


http://www.hwupgrade.org/public/style_emoticons/default/coolface.png
Embé? Quel modulo utilizza una funzionalità avanzata che generalmente viene utilizzata dai debugger, il tracing.

Tra l'altro questo tipo di goto sono soggetti a restrizioni, che derivano dalla funzionalità di tracing (e quindi dal funzionamento della virtual machine).

Ciò detto, non conoscevo questo modulo, e dubito che lo usino i pythonisti.
I sorgenti di Python:

Python 2.7:
http://img826.imageshack.us/img826/3893/python273goto.jpg

Python 3.3:
http://img254.imageshack.us/img254/6051/python333goto01.jpg
http://img267.imageshack.us/img267/8361/python333goto02.jpg

Però è il colmo: considerano il costrutto goto il male assoluto(tant'è che non lo implementano nel linguaggio) ma non si fanno scrupoli nell'utilizzarlo in CPython per aumentare le prestazioni :rolleyes:

:D
Infatti sono due cose completamente diverse: il linguaggio è Python, che ha una sua sintassi.

Quella di cui hai postato gli screenshot è una implementazione, quella più diffusa, che si chiama CPython ed è scritta in un linguaggio povero di costrutti sintattici, il C.

Inoltre se i compilatori fossero migliori, potrebbero riconoscere quei casi di codice duplicato e ottimizzare l'eseguibile generando internamente i salti all'unica porzione di codice.

Infine i "computed goto" vengono usati esclusivamente nelle piattaforme che fanno uso di GCC come compilatore, che mette a disposizione questo costrutto completamente fuori standard (do you remember "Embrace, Extend, Extinguish"?).
Negli altri compilatori che seguono gli standard non li trovi e ovviamente non vengono usati.
D'altronde cos'è un blocco try/catch se non un goto camuffato, un eufemismo per saltare da qualche parte senza scrivere la parola "goto"?
Secondo me stai confondendo il concetto di GOTO con quello classico di SALTO. Il secondo è una pietra miliare dell'informatica, e non se ne può fare a meno. Il primo... no.

Esempio classico: l'IF. Togliendo di mezzo le architetture che dispongono di esecuzione condizionale delle istruzioni, un if viene tradotto in linguaggio macchina con un test e un SALTO. Normale amministrazione.

Anche il GOTO viene tradotto con un SALTO, ma in questo caso il GOTO è un costrutto sintattico di più alto livello, come lo è l'IF, il WHILE, il FOR, il TRY, il WITH (per Python), il DO (C et similia), ecc. ecc.

Fanno tutti uso del SALTO internamente, e mi pare anche normale che sia così (come li implementeresti altrimenti?).

Il punto, però, è che il GOTO è un costrutto di molto basso livello (rispetto agli altri), usato in linguaggi come il C che sono particolarmente poveri a livello di altri costrutti sintattici che sono molto più comodi e di più facile manutenibilità.

C'è bisogno che ti ricordi da dove deriva il concetto di "spaghetti basic"? Dall'uso smodato del GOTO. Non a caso...

Vincenzo1968
28-12-2012, 11:49
Si tratta di un'implementazione specifica del compilatore GCC ma sempre goto è.

Io non li critico per averlo utilizzato. Per me, se rende il propramma più veloce, hanno fatto benissimo a utilizzarlo. Mettevo in risalto, però, una certa incoerenza: il goto considerato male assoluto(tant'è che lo escludono dal linguaggio) ma loro non si fanno problemi a utilizzarlo nell'implementazione di CPython. Potevano benissimo farne a meno. È sempre possibile sostituire i goto con qualche altro costrutto come mirabilmente spiegato nell'articolo di Knuth.

cdimauro
28-12-2012, 12:39
Sì, ma se il compilatore non genera codice ottimizzato, vi si ricorre. Purtroppo.

Non è questione di mancanza di coerenza. Python e CPython sono due cose completamente diverse, come già detto. Quest'ultimo deve avere a che fare sia col C, che è un linguaggio povero di costrutti (niente eccezioni; si vede da come il codice sia farcito di if per controllare se il risultato non abbia generato un problema), che coi compilatori che non ottimizzano adeguatamente il codice e costringono all'uso dei GOTO.

Questo finché PyPy non prenderà il posto di CPython. PyPy è scritto in RPython (un sottoinsieme stretto di Python), e ovviamente lì GOTO non ce ne sono...