Quali utili strutture di controllo alternative conosci? [chiuso]


12

Una domanda simile è stata chiusa su SO.

A volte, quando stiamo programmando, scopriamo che una particolare struttura di controllo potrebbe esserci molto utile, ma non è direttamente disponibile nel nostro linguaggio di programmazione.

Quali strutture di controllo alternative pensi siano un modo utile di organizzare il calcolo?

L'obiettivo qui è quello di ottenere nuovi modi di pensare alla strutturazione del codice, al fine di migliorare blocchi e ragionamenti.

È possibile creare una sintassi desiderata / semantica non disponibile ora o citare una struttura di controllo meno nota su un linguaggio di programmazione esistente.

Le risposte dovrebbero fornire idee per un nuovo linguaggio di programmazione o per migliorare un linguaggio reale.

Pensa a questo come un brainstorming, quindi pubblica qualcosa che ritieni sia un'idea folle ma può essere praticabile in alcuni scenari.

Riguarda la programmazione imperativa.


1
Perché questa domanda deve riguardare la "programmazione imperativa"?
missingfaktor,

@missingfaktor: Perché le strutture di controllo riguardano la programmazione imperativa. Certo, alcuni problemi possono essere risolti con un approccio funzionale o in altro modo, ma altri paradigmi non mettono le strutture di controllo al centro dello sviluppo. Ma comunque puoi essere creativo.
Maniero,

3
Bene, stavo per condividere Pattern Matching con Guards, dal momento che quelli sono più generici di Case case e If-Thens, ma se questa non è una zona FP, immagino che sia solo più Pattern Matching per il resto di noi!
CodexArcanum,

@CodexArcanum: Beh, Pattern Matching è un costrutto molto simile ai costrutti imperativi. In effetti, Pattern Matching stesso è un'alternativa alle strutture di controllo imperative. Non essere timido ;-)
Maniero,

Guardare tutte le risposte mi rende felice che nessuna delle proposte esiste nella vita reale (e si spera che non lo farà mai). Mi dispiace :)
serg

Risposte:


14

OK, questa è una domanda divertente.

Vorrei anche avere un generale elseper while e per loop, per quando la condizione non è vera al primo test:

while (condition) {
    // process
}
else {
    // condition was never true
}

Questo evita l'imbarazzante ricalcolo della condizione o la sua memorizzazione in una variabile.


Python ha questo.
Barry Brown,

Hey! Finalmente una strana scelta di Python con cui sono d'accordo! ;-)
Macneil,

5
No. La clausola else in Python per / mentre i cicli viene eseguita se il ciclo termina normalmente, il che significa che il ciclo non viene terminato tramite un'istruzione break o return o un'eccezione. In for loop, il clasuse else viene eseguito dopo che la sequenza di elementi su cui è stato eseguito il loop si è esaurito, mentre in loop viene eseguita dopo che la condizione di loop viene valutata per la prima volta su False.
Pillmuncher,

4
C'è una richiesta per aggiungere il while ... elsecostrutto nel modo in cui Macneil lo descrive a PHP. Penso che sia un'ottima idea, perché "qui ci sono i risultati / non ci sono risultati" è un linguaggio abbastanza comune nelle app web.
Dean Harding,

1
@SnOrfus: Vuole un blocco di codice (separato dal blocco del ciclo) che viene eseguito SOLO se la condizione while non viene mai soddisfatta. Do-While esegue il blocco di codice del loop (non un blocco separato) una volta indipendentemente dal condizione condizionale.
Legione,

10

Perché non mescolare alcune risposte in una?

while (expr) {

    // Executed every iteration, unless first{} is present.
    // May be explicitly called rest{} if you like first{} to come first.

    // Blocks may return results, and consequently be used in expressions.
    return expr;

} first {

    // Executed only on the first iteration.

} pre {

    // Executed before every iteration.

} post {

    // Executed after every iteration.

} catch (oops) {

    // All blocks are implicitly try{}ed if followed by a catch{}.

} finally {

    // Executes after the block completes, regardless of exceptions.

} else {

    // Executed if the loop body or rest{} never executes.

} never {

    // Executes only when a client is present.

} drop (bad, worse), // Explicitly ignore certain exceptions.
  until (expr);      // Here, have a post-body condition, too.

Una sintassi costruttiva estensibile e generalizzata di controllo del flusso in un linguaggio imperativo sarebbe piuttosto utile e divertente. Fino a quando non si presenta, suppongo che userò semplicemente Lisp o qualcosa del genere.


5
Non utile, confuso. Non divertente, lento.
Josh K,

2
@Josh K: Sì, hai ragione. Cosa, hai pensato che non sarei d'accordo? Questa risposta si sta mordendo la lingua per non ridere.
Jon Purdy,

Se fosse voluto dall'ironico, sicuramente ci riuscì!
Josh K,

11
+1 Mi ha fatto ridere. Richiede una clausola "Between", affinché il codice venga eseguito tra le iterazioni.
Barry Brown,

1
+1, ma ha bisogno anche di un seventh { ... }.
j_random_hacker

7

Strutture di controllo come funzioni.

Voglio for, if, else, while, ecc per essere funzioni, non strutture speciali.

Io voglio return, try/excepte gotodi essere derivati di continuazioni.

Questo ovviamente ha meno a che fare con una particolare struttura di controllo e più con il modo in cui vedi le strutture di controllo in generale, il meta delle strutture di controllo.


2
Le continuazioni sono un concetto pesante per una lingua e ci sono buone ragioni per lasciarle fuori da molte lingue.
David Thornley,

Non sono in disaccordo; avendo for, if, else, e whilecome funzioni mi fa dedurre che i parametri a tali funzioni devono essere pigramente eseguito al fine di comportarsi allo stesso come i costrutti originali. Avere la capacità di eseguire un'esecuzione pigra sarebbe bello.
Apprendista Dr. Wily,

1
@ David: Solo perché sono lì non significa che devi usarli. I programmatori regolari possono usare ciò a cui sono abituati return, le eccezioni, ecc. Ma ora il programmatore esperto ha un potente strumento aggiuntivo nella sua cassetta degli attrezzi se necessario. Inoltre, le lingue IMHO non dovrebbero essere "messe a tacere". Le lingue dovrebbero avere la capacità di supportare una maggiore competenza e crescita delle conoscenze CS.
dietbuddha,

1
@dietbuddha: (cont) Non sto dicendo che le continuazioni siano cattive, sto dicendo che sono dei pesi massimi, e renderle utilizzabili ha implicazioni per il linguaggio, come fanno le eccezioni. Inoltre, avere delle continuazioni probabilmente forzerà i cambiamenti nel modo in cui le persone usano il linguaggio, come le eccezioni in C ++. Un linguaggio che supporta le continuazioni sarà diverso da uno che non lo è, sia in modo positivo che negativo.
David Thornley,

1
@ Steve314 - longjmp non è una continuazione anche se ci sono somiglianze. Le continuazioni salvano l'intero stato (tutti i locali, i globali e lo stack). longjmp salva un puntatore dello stack, quindi se si supera l'ambito in cui è stato utilizzato setjmp si ottiene un segfault poiché il frame non esiste più. Credo che ci siano anche alcune limitazioni nelle variabili che salva.
dietbuddha,

6

L'articolo collegato ha decisamente ragione sui N + 1/2 Loops di Donald Knuth . Espresso in C / C ++ / Java:

for (;;) {
  get next element;
  if (at the end) break;
  process the element;
}

Ciò è utile per leggere righe o caratteri da un file, verificare se hai raggiunto EOF e quindi elaborarlo. Sono così abituato a vedere for(;;)..if(..)break;apparire lo schema che è idiomatico per me. (Prima di leggere l'articolo Knuth, ristampato nel libro Literate Programming , questo era un "wtf?".)

Knuth ha suggerito le parole chiave loop/while/repeat:

loop:
  S;
while C:
  T;
repeat

Dove Se Tsono i segnaposti per una serie di zero o più dichiarazioni ed Cè una condizione booleana. Se non ci fosse alcuna Sistruzione, sarebbe un ciclo while e se non ci fosse alcuna Tdichiarazione, sarebbe un ciclo do.

Questo costrutto stesso potrebbe essere generalizzato consentendo zero o più while Cclausole, rendendolo perfetto per esprimere infiniti loop e quindi alcune condizioni più rare che richiederebbero due controlli.

Nello stesso articolo, Knuth ha suggerito un meccanismo di segnalazione che sarebbe una versione locale delle eccezioni di lancio / cattura (in alternativa all'utilizzo di goto).

Per me? Vorrei che Java supportasse l'ottimizzazione delle chiamate in coda, in modo da poter esprimere qualsiasi struttura di controllo generale, se necessario.


Aggiornamento: ho dimenticato di menzionare che molti programmatori C / C ++ / Java aggirano questo usando un compito incorporato nelle condizioni di while:

while ((c = getc(f)) != -1) {
   T;
}

Usando i termini del costrutto di Knuth, questo è consentito quando Se Cpuò essere combinato in una singola espressione. Alcune persone odiano vedere l'incarico incorporato sopra, mentre altri odiano vedere breakquanto for (;;)sopra. Ma quando Se Cnon possono essere combinati, come quando Sha più istruzioni, for (;;)è l'unica alternativa senza ripetere il codice. L'altra alternativa è semplicemente duplicare il Scodice:

S;
while (C) {
  T;
  S;
}

L' loop/while/repeatalternativa di Knuth sembra molto meglio.


Quel loop-while-repeat assomiglia molto al repeat-untilloop Pascal .
Mason Wheeler,

@Mason: la differenza è che ci sono due posti in cui puoi inserire istruzioni più la tua condizione, non solo una.
Macneil,

Oh, vedo cosa sta succedendo. Sì, è interessante ...
Mason Wheeler,

ANSI Basic aveva un do while ... loop until: sia la precondizione che la postcondizione sono opzionali e io (vagamente) ricordo di averli usati entrambi in un ciclo. Per la tua condizione media, c'è l'Ada exit when ...;. Il vantaggio principale if ... break;è che puoi scrivere exit loopname when ...;per uscire da più (ma non necessariamente tutti) cicli annidati contemporaneamente. Probabilmente anche leggermente più visibile di quella pausa.
Steve314,

Cosa divertente. Ada ha esattamente questa funzione.
John R. Strohm,

6

Il linguaggio BCPL aveva valueofun'espressione che poteva essere usata per trasformare una sequenza di istruzioni in una singola espressione:

foo(a, b, valueof {some series of statements; resultis v});

Dove some series of statementspuò essere qualsiasi cosa e il tutto valueofvaluta v.

Questo potrebbe essere utile in Java per quando è necessario calcolare un argomento per chiamare un this()o super()(che richiede che non accada nulla prima di esso). Naturalmente, potresti semplicemente scrivere un metodo separato, ma potrebbe essere una seccatura se devi passare molti valori locali per il contesto.

Se sei in grado di utilizzare finalper le variabili necessarie, puoi già fare un valueofin Java usando classi interne anonime:

foo(a, b, new Object(){String valueof(){
    String v ...; some series of statements; return v;}}.valueof());

1
GCC ha un'estensione per questo - ({ statement1; statement2; ...; result-expr; }). Ho visto simili anche altrove, ma non ricordo dove. Probabilmente tutti copiati da BCPL, però.
Steve314,

6
unless(condition) {
  // ...
}

fa la stessa cosa di:

if(!condition) {
  // ...
}

repeat {
  // ...
} until(condition)

fa la stessa cosa di:

do {
  // ...
} while(!condition)

Potresti voler andare a Lisp ...
durante il

1
O Ruby, ha una sintassi simile per unless.
Josh K,

2
Sembra abbastanza perlish. C'è più di un modo per farlo.

2
@ Steve314 È necessario utilizzare uno stile di parentesi graffa errato . ;-)
Orbling

1
@Orbling - per niente. Tutti gli altri usano uno stile di parentesi graffa errato.
Steve314,

5

In una nota diversa, vorrei vedere un migliore supporto per gli iteratori nei linguaggi di programmazione. In particolare, per quando vuoi scendere due raccolte in coppia :

for (String s, Integer i : stringsSet, integersSet) {
    // use the pair (s, i)
}

Alcuni linguaggi dinamici potrebbero già avere questo, o supportare facilmente tramite librerie e macro, ma penso che questo sia nello spirito della tua domanda.

Se i due set non hanno le stesse dimensioni, potrebbe generare un'eccezione o si potrebbe avere un elseciclo successivo per segnalare che c'era una differenza nelle dimensioni.

Naturalmente, potresti generalizzare questo per andare giù tre o più liste.


Aggiornamento: utile anche fare il prodotto cartesiano tra iterabili:

for (String s, Integer i : stringsSet * integersSet) {
    // use the pair (s, i), each s with each i
}

che non sarebbe altro che anelli nidificati:

for (String s : stringsSet) {
    for (Integer i : integersSet) {
        // use the pair (s, i), each s with each i
    }
}

Sono un po 'preoccupato che tra le due notazioni che ho fornito qui ci sia una differenza O (n) e O (n ^ 2) nel numero di coppie, con solo il cambiamento di un singolo carattere.


2
In Python ci sono zip e zip_longest che lo fanno.
pillmuncher,

Bene, forse sto sottovalutando Python e dovrei dargli una seconda occhiata dopo molti anni. Questo mi ricorda, a volte anche tu vuoi il prodotto cartesiano, l'equivalente di loop annidati.
Macneil,

1
Entrambi questi casi in Scala: paste.pocoo.org/show/297429
missingfaktor

1
In riferimento al prodotto cartesiano: Ancora una volta, Python ce l'ha. for a, b, c in itertools.product(iter1, iter2, iter3):ti dà il prodotto cartesiano valutato pigramente. Cos'è quello? Vuoi anche permutazioni e combinazioni di un dato iteratore? itertools.permutations, itertools.combinations.
aaronasterling

1
Prospettiva di Haskell: usare "zipWith" per il primo caso e la comprensione dell'elenco o la monade Elenco per il secondo. Come gli exmaples di Python / Scala, ma più eleganti. :)
LennyProgrammers

5

Esiste il cosiddetto "Dijkstra's Loop" (chiamato anche "Dijkstra's Guarded Loop"). È stato definito in The Guarded Command Language (GCL) . Puoi trovare alcune informazioni a riguardo sintassi e semantica nell'articolo di Wikipedia sopra nella sezione 6 Ripetizione: do .

Oggi conosco un linguaggio di programmazione che supporta direttamente questa struttura di controllo. È Oberon-07 (PDF, 70 KB). E supporta "Dijkstra's Loop" nella forma di dichiarazione while. Dai un'occhiata alla sezione 9.6. Mentre dichiarazioni nel PDF sopra.

WHILE m > n DO m := m – n 
ELSIF n > m DO n := n – m 
END

PS Questa è una copia della mia risposta SO .


Sembra che anche il correttore di modelli Spin abbia questo costrutto, con semantica identica e sintassi sostanzialmente identica.
j_random_hacker

4

Espressioni in stile icona con backtracking incorporato.

Python ottiene molti dei vantaggi del generatore di icone e ne fa un lavoro migliore in generale, IMO. E in linea di principio il backtracking era solo una sorta di eccezione, ma era la semplicità delle espressioni l'equivalente approssimativo di ...

x = (a / b) else c;

gestire i casi di fallimento come divisione per zero.

Dove Icon è impazzito - nessun operatore di confronto di ritorno booleano. I confronti hanno sempre avuto successo o innescato il backtracking, e c'era qualche altro problema semantico che ora sto disperatamente cercando di ricordare che ... beh, diciamo solo che probabilmente è più represso che dimenticato.

Ho sempre pensato che avrebbero dovuto avere ifun'espressione senza altra parte - if (condition, success-value)qualcosa del genere, tornare indietro se la condizione restituiva falso - e abbandonare gli strani confronti.

EDIT Ricordo - ovvio davvero. Un confronto con due argomenti ha esito positivo o negativo: non restituisce un nuovo valore da restituire. Così, quando ci si riesce, ciò non è tornare? Risposta: uno degli argomenti. Ma se scrivi a > b, qual è l'argomento logico da restituire - ao b? E se b < ainvece scrivessi ? Penso che abbia sempre restituito l'argomento giusto, che ha più senso di qualsiasi cosa, ma di solito mi è sembrato l'argomento sbagliato.


4

Questa è solo un'idea generale e una sintassi:

if (cond)
   //do something
else (cond)
   //do something
also (cond)
   //do something
else
   //do something
end

ANCHE la condizione viene sempre valutata. ELSE funziona come al solito.

Funziona anche per caso. Probabilmente è un buon modo per eliminare la dichiarazione di rottura:

case (exp)
   also (const)
      //do something
   else (const)
      //do something
   also (const)
      //do something
   else
      //do something
end

può essere letto come:

switch (exp)
   case (const)
      //do something
   case (const)
      //do something
      break
   case (const)
      //do something
   default
      //do something
end

Non so se sia utile o semplice da leggere ma è un esempio.


3

Continuing Passing Style mi viene in mente. Quindi, ovviamente, anche tu vorresti avere l' ottimizzazione delle chiamate di coda .


1
Non è un grande fan di questo, e non credo che sia davvero una "struttura di controllo", ma piuttosto un mattone nei linguaggi funzionali e nello stile di programmazione. Node.js sembra piuttosto agganciato su di esso però.
Josh K,

1
Naturalmente è una struttura di controllo. Non è solo uno che viene fornito con una parola chiave come 'if' o 'for', ma come modello per strutturare il flusso di controllo (quindi, struttura di controllo). È anche usato dietro le quinte da molti compilatori. E non si limita nemmeno ai FL. Tuttavia, sono necessarie funzioni come oggetti di prima classe.
pillmuncher,

1
Oggigiorno si ottiene l'ottimizzazione delle chiamate in coda in C e C ++, ma IMO non ha senso. Il punto è che si tratta di un'ottimizzazione. In Scheme, una vera chiamata di coda è ovvia. Soprattutto in C ++, molte cose possono significare che la tua coda non è una coda. E lo stack overflow significa che l'app è rotta. IMO, dovrebbe esserci qualcosa come goto return ...;un'istruzione, che rende esplicita l'intenzione di chiamare in coda, quindi se il compilatore non può renderlo iterativo è un errore.
Steve314,

1
@Macneil - che conosco per certo, l'ottimizzazione delle chiamate di coda viene eseguita in GCC, Clang e Visual C ++. GCC ha conversioni più sofisticate dalla ricorsione all'iterazione, in grado di gestire un numero di casi che non sono ricorsione della coda. Ma molto può andare storto. Passa un puntatore a una variabile locale in quella chiamata di coda e il frame dello stack non può essere eliminato, poiché la variabile deve essere mantenuta attiva. In C ++, normalmente i distruttori di variabili locali si verificano dopo il ritorno della chiamata "tail", il che significa che non è affatto una chiamata tail.
Steve314,

1
@ Mike - questo è il mio punto. Se si utilizza uno stile di codifica ricorsivo, senza la "coda" di ottimizzazione, il codice è potenzialmente interrotto, poiché l'overflow dello stack è un errore. In C ++ è un'ottimizzazione - per il compilatore fare ottimizzazioni in modo da non dover andare bene, ma non puoi fare affidamento su di esse. Se vuoi la libertà di scrivere in stile ricorsivo, ma non devi preoccuparti dei problemi di profondità dello stack, l'eliminazione della coda non è ottimizzazione, è un problema di correttezza. Se la ricorsione è il modo migliore per codificare qualcosa, dovresti essere in grado di farlo - non devi preoccuparti di overflow dello stack.
Steve314,

3

Diramazione di thread senza soluzione di continuità, ha una sintassi simile a una funzione, ma viene eseguita in un thread separato e non può accedere ai dati che non sono stati inizialmente passati ad essa.

branch foo(data, to, be, processed){
    //code
    return [resulting, data]
}

Quando viene chiamato un ramo, restituirà immediatamente un handle.

handle=foo(here, is, some, data)

L'handle può essere utilizzato per verificare se l'attività è stata eseguita.

handle.finished() //True if the execution is complete

Se il risultato viene richiesto prima che l'esecuzione sia completa, il thread principale semplicemente attenderà.

[result, storage]=handle.result()

Ciò non coprirebbe gli scenari di multithreading più avanzati, ma piuttosto fornirebbe un modo facilmente accessibile di iniziare a utilizzare più core.


Dai un'occhiata a Cilk, è un'estensione molto pulita e semplice di C: en.wikipedia.org/wiki/Cilk . Non so se ha un handle.finished()test, ma spawne syncsono tutto ciò che serve per il 90% delle attività di programmazione parallela.
j_random_hacker

3
if (cond)
   //do something
else (cond)
   //do something
else (cond)
   //do something
first
   //do something
then
   //do something
else (cond)
   //do something
else
   //do something
end

I blocchi FIRST e THEN vengono eseguiti se uno qualsiasi dei 3 condizionali viene valutato su true. Il PRIMO blocco viene eseguito prima del blocco condizionale e POI viene eseguito dopo l'esecuzione del blocco condizionale.

La scrittura condizionale o finale ELSE successiva all'istruzione FIRST e THEN sono indipendenti da questi blocchi.

Può leggere come:

if (cond)
   first()
   //do something
   then()
else (cond)
   first()
   //do something
   then()
else (cond)
   first()
   //do something
   then()
else (cond)
   //do something
else
   //do something
end


function first()
   //do something
return
function then()
   //do something
return

Queste funzioni sono solo un modulo da leggere. Non avrebbero creato ambito. È più come un gosub / ritorno da Basic.

Utilità e leggibilità come argomento di discussione.


2

A volte mi ritrovo a scrivere un ciclo che deve fare qualcosa di diverso durante la prima iterazione. Ad esempio, visualizzando i tag <th> anziché <td>.

Gestisco questa situazione con una bandiera booleana. Qualcosa come questo:

first = true

while (some_condition)
    if (first)
        do_something
        first = false
    else
        do_something_else

Sembra sciocco controllare il valore di firstogni iterazione quando sarà falsa per la maggior parte del tempo.

Vorrei avere un'opzione di loop per specificare un corpo del loop diverso sulla prima iterazione. Non ci sarebbe bisogno di una variabile separata. Il codice compilato non ne avrebbe nemmeno bisogno, perché il codice generato avrebbe due corpi, uno per la prima iterazione e uno per il resto.


La domanda SO ha un'idea simile, ma con un operatore "then" da utilizzare sui valori. In questo modo, probabilmente non hai un codice duplicato. Ad esempioprint(out, first "<th>" then "<td>")
Macneil,

1
Il modo migliore è iniziare l'iterazione +1.
Josh K,

1
Il caso comune è il looping con la gestione tra, ad esempio elencare gli elementi con un separatore virgola. In senso stretto, è if (!first) gimme-a-comma ();la stessa cosa. Un'obiezione che avrei, però - se lo avvolgi appropriatamente finirai con cose come il metodo join stringa Python - comunque spesso hai bisogno del modello di base, il ciclo sottostante non deve essere riscritto così spesso.
Steve314,

Come dice Josh, ovviamente, è valido estrarre il primo oggetto dal ciclo. Nel caso del separatore virgola significa codice duplicato, ma può essere una chiamata di funzione duplicata. Personalmente, preferisco l'inefficienza di if (!first), ma i micro-ottimizzatori possono sollevare obiezioni sulla previsione del ramo.
Steve314,

1
@Barry Brown: srotolare la prima iterazione del loop potrebbe essere o meno veloce rispetto al controllo di un flag booleano. Un predittore di ramo decente sbaglia nel peggiore dei casi le prime 2 iterazioni, prevedo :) Preferirei usare if (!first)e lasciare che un compilatore ottimizzante decida se il corpo del loop è abbastanza piccolo da srotolarlo e liberarsene first.
j_random_hacker

1

[copiato dalla mia risposta su stackoverflow]


ignoring - Ignorare le eccezioni che si verificano in un determinato blocco di codice.

try {
  foo()
} catch {
  case ex: SomeException => /* ignore */
  case ex: SomeOtherException => /* ignore */
}

Con un costrutto di controllo ignorato, potresti scriverlo in modo più conciso e più leggibile come:

ignoring(classOf[SomeException], classOf[SomeOtherException]) {
  foo()
}

[Scala fornisce questo (e molti altri costrutti di controllo di gestione delle eccezioni) nella sua libreria standard, nel pacchetto util.control. ]


4
Le eccezioni non dovrebbero essere ignorate.
Josh K,

1
Solo che, nel contesto, un'eccezione potrebbe non essere un errore.
Steve314,

1
@Josh, @Steve: ci sono casi in cui vorresti ignorare le eccezioni. Vedi questa discussione per alcuni di questi casi.
missingfaktor il

Un'eccezione è un avviso che qualcosa potrebbe essere sbagliato. Un try..catchblocco vuoto è una cosa; ti costringe a riconoscere l'errore e ignorarlo deliberatamente; mentre gettare pezzi di codice sotto un ignore globale può portare a problemi quando si generano tali eccezioni, nonché a cattive abitudini di programmazione.
Josh K,

@Josh - Ho appena cancellato due commenti perché non stavo pensando bene - ma le speranze sono alte per questo. Se questa affermazione è globale, probabilmente sono d'accordo - ma a me sembra una struttura a blocchi. IOW è come un tryblocco, tranne che elenca le eccezioni che rileva e ignora in anticipo, invece che in seguito. Potrebbe anche essere un vantaggio di leggibilità, ad esempio far sapere al lettore che un file mancante non è un errore anche prima di leggere la chiamata aperta.
Steve314,

1

Invece di:

switch(myEnum) {
  case MyEnum.Val1: do1(); ...
  case MyEnum.Val2: do2(); ...
....

Fallo in Python, o ora anche in C #:

action = val2func[myEnum]
action()

Scala ha molte nuove funzionalità.

Infine, lingue come Clojure possono essere estese per fornire funzionalità extra.


1
C può fare anche questo. E Pascal. Probabilmente tutte quelle vecchie lingue degli anni '70 / '80 / '90. Un array di funzioni diventa un array di puntatori di funzioni, ma non è un grosso problema. Dove diventa più facile è quando hai funzioni anonime - sai, come in Lisp, ML, ...
Steve314,

Steve314 - correzione - questo è un esempio di dizionario che associa qualsiasi valore a una funzione. È qui che le cose diventano leggermente più pulite di quanto potrebbero fare la maggior parte delle cose degli anni '70 / '80 / '90.
Giobbe

1

Ho due idee.

Spesso trovo che mi sto ripetendo a catchblocchi. Questo può essere in qualche modo aiutato attraverso l'estrazione di metodi, ma ciò può causare disordine inutile se i metodi sono molto brevi o altrimenti non meritevoli di un metodo. Quindi, sarebbe bello nidificare i catchblocchi:

try {
    // Save something
} catch (Exception e) {
    // Something we do for all Exceptions
    catch (ProcessingException e) {
        // Something we do for all Processing exceptions
        catch (DBExcpetion e) {
            // DBExceptions are a subclass of ProcessingException
        }
        catch (BusinessRuleException e) {
            // BusinessRuleExceptions are also a subclass of ProcessingException
        }
    }
    // Something we do after specific sub class Exceptions
 }

Nella programmazione web spesso mi trovo spesso a fare qualcosa del genere (questo non è un vero esempio, quindi non analizzare casi di fantasia):

Account a = getSavedAccount();
if (a == null) {
    a = getAccountFromSessionId();
}
if (a == null) {
    a = getAccountFromCookieId();
}
if (a == null) {
    a = createNewAccount();
}

In Javascript (bene, ECMAScript e forse altri con cui non ho familiarità), dato che qualsiasi valore può essere valutato come condizione, ||può aiutare.

var a = getAFromLocation1() || getAFromLocation2() || default;

Mi piace molto come appare e vorrei che più lingue, in particolare alcune sul lato server, avessero il supporto per questo. (PHP può valutare qualsiasi cosa come condizione, ma converte l'intera espressione condizionale in un valore booleano invece di preservare il valore. Non so Python o Ruby.) Potrebbe diventare ingombrante dopo circa tre casi, ma se ne hai di più di tre casi, potresti anche avere un cattivo design del software.


Python fa qualcosa di simile al tuo || valutazione, ma quando finalmente ottenne la sua x if c else ysintassi delle espressioni condizionali , una delle ragioni principali che accadde fu perché molte espressioni che usavano queste semantiche per ||e &&erano buggy. IIRC un caso comune era un valore (come zero) valido per l'applicazione da trattare false, quindi scartato in modo da utilizzare invece un fallback non valido. Comunque - vedi la mia risposta WRT il linguaggio di programmazione Icon, che può avere espressioni simili get1() else get2() else default.
Steve314,

1

Switch generalizzato ha detto sopra:

 switch(x){
  predicate1:
     dosomething();
  predicate2:
     dosomethingelse();
 }

In Haskell:

  switch' :: a -> [(a -> Bool, b)] -> b
  switch' a [] = undefined
  switch' a (f,b):xs = if f a
                     then b
                      else switch' a xs

0

In C # vorrei usare semplici switch () { ... }, ma estensibili con tali espressioni:

switch (value)
{
  // string-based operators:
  case begins "Maria": // to catch Maria Carey
    break;
  case ends "Washington": // to catch George Washington
    break;
  case like "ph": // to catch Phil, Phillip, Sophie
    break;
  case between "Aaron" and "April": // to catch all names between
    break;

  // use non-static variables in case expression:
  case Dao.GetDefaultBabyName():
    break;

  // continuable cases without breaking
  case "John":
    bonus = 25;
  case "Peter":
    salary = 500;
    break;

  // jumps between cases
  case "Aleron":
    // do something
    break;
  case "Bella":
    // do something
    jump "Aleron";
    break;

}

E così via. Lo stesso con i numeri o altri tipi (che supporta IComparable, IConvertible, ...)

Questo potrebbe rendere il mio codice più laconico e leggibile.


Fall-through su casi è un male noto, e in genere sto bene senza di essa. E i salti sono troppo GOTO per qualsiasi programmazione sana. Ma avere espressioni e non statica nel caso sarebbe un'aggiunta adorabile.
CodexArcanum,

0

È una domanda divertente, come ha detto @Macneil.

La mia insolita struttura di controllo preferita, che ho scoperto (umile tosse), è l' esecuzione differenziale .

Ha alcuni usi. Per me l'uso schiacciante è nella programmazione delle interfacce utente, che è un'istanza del problema più generale di conservazione dei dati ridondanti in corrispondenza. Da un lato, ci sono dati dell'applicazione e, dall'altro, ci sono controlli UI, che devono essere mantenuti d'accordo. Sembra "vincolante", ma in realtà c'è molto di più.

Di solito lo implemento con le macro in C o C ++. In C # devo farlo con istruzioni espandibili a mano. Questo è un dolore, ma funziona.

Una volta l'ho implementato in termini di macro Lisp, e poi è stato molto pulito. Non ha richiesto attenzione da parte del programmatore. Avrei potuto fare la stessa cosa in qualsiasi altro linguaggio strutturato se avessi avuto il problema di scrivere un parser completo e quindi generare tutte le cose giuste. È un grande progetto e non l'ho fatto.


0

Strutture di controllo "tradizionali" come quella fordel controllo del lavoratore, lo mantengono sottomesso alle ideologie corrotte dell'élite capitalista al potere. Ecco perché uso ph0rinvece strutture di controllo alternative come . È come for, ma più radicale: non ti accorgerai di ph0rindossare giacca e cravatta, spargendo qualche BS aziendale. ph0rmantiene reale, amico.

Combatti il ​​potere!


0

forLoop più semplice

for(100)
{
    //Will run for 100 times
}


for(i)
{
    //Will run for i times while i must be a positive integer
}


for(i as a)
{
    //Will run for i times while i must be a positive integer
    //and a is the incremental loop variable starting from 0 and 
    //scoped within the loop
}


for(i as a=2)
{
    //Will run for i times while i must be a positive integer
    //and a is the incremental loop variable starting from 2 and 
    //scoped within the loop
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.