Perché non esiste una lingua che supporti un if..elseif..anche ... la costruzione? [chiuso]

0

Non per la prima volta, volevo fare qualcosa del genere:

if condition1
  result1
elseif condition2
  result2
else
  result3
else result4, so 'if result3 did not run' then run result4.

Ma questo non esiste. Si potrebbero annidare i if o usare variabili aggiuntive, ma entrambi sono più complicati da scrivere e leggere. Invece, la mia soluzione suggerita a questo problema sarebbe un costrutto linguistico come questo:

if condition1
  result1
elseif condition2
  result2
any
  result4
else
  result3

Che funzionerebbe per qualsiasi numero di elseif.

Questo è nuovo, quindi la gente dovrà impararlo, ma molti linguaggi hanno cose non standard, come obj.each do |item| di Ruby, except ... else di Python o%% di Java di Java. Leggendo questo costrutto per la prima volta senza un'introduzione, si può o non si può ottenere subito, ma non è un concetto terribilmente difficile da cogliere o cercare. Inoltre, non vedo problemi tecnici come l'ambiguità che impedirebbero l'implementazione.

Mi manca qualche motivo per cui non è possibile implementarlo o perché non dovrebbe essere implementato? (Queste sono due domande separate.)

    
posta Luc 26.02.2016 - 15:44
fonte

8 risposte

4

Ogni caratteristica della lingua ha un costo. Potrebbe essere un costo aggiuntivo di complessità per il parser. Potrebbe essere un costo opportunità in non implementare altre funzionalità linguistiche. Potrebbe essere il costo di far lavorare gli sviluppatori su di esso. Potrebbe essere un costo aggiuntivo di test e l'eventuale incompatibilità all'indietro. Potrebbe essere il costo del futuro "perché abbiamo aggiunto questo?" discussioni quando causa un conflitto con altre funzionalità desiderate.

In ogni caso, c'è un costo per ogni funzione che viene inserita nella lingua. E quindi, c'è anche un ritorno sull'investimento - il costo che abbiamo affondato nella funzione migliora il linguaggio per le persone che lo usano più di qualche altra funzione e il suo costo che noi non abbiamo fatto.

In Minus 100 punti di Eric Gunnerson , descrive il processo dello sviluppo del linguaggio per C #.

So, we decided on the additive approach instead, and worked hard to keep the complexity down. One way to do that is through the concept of “minus 100 points”. Every feature starts out in the hole by 100 points, which means that it has to have a significant net positive effect on the overall package for it to make it into the language. Some features are okay features for a language to have, they just aren't quite good enough to make it into the language.

E in Il futuro di C # di Eric Lippert , Prima parte

After we finished the last-minute minor redesigns of various parts of C# 3.0, we made a list of every feature we could think of that could possibly go into a future version of C#. We spent many, many hours going through each feature on that list, trying to “bucket” it. Each feature got put into a unique bucket. The buckets were labelled:

Pri 1: Must have in the next version
Pri 2: Should have in the next version
Pri 3: Nice to have in the next version
Pri 4: Likely requires deep study for many years before we can do it
Pri 5: Bad idea

Obviously we immediately stopped considering the fours and fives in the context of the next version. We then added up the costs of the features in the first three buckets, compared them against the design, implementation, testing and documenting resources we had available. The costs were massively higher than the resources available, so we cut everything in bucket 2 and 3, and about half of what was in bucket 1. Turns out that some of those “must haves” were actually “should haves”.

Understanding this bucketing process will help when I talk about some of the features suggested in that long forum topic. Many of the features suggested were perfectly good, but fell into bucket 3. They didn’t make up the 100 point deficit, they just weren’t compelling enough.

Anche se questo non è necessariamente il processo per tutte le lingue, è ciò che probabilmente accade in molte menti. Avere tutto e il lavandino della cucina non è un buon design (guarda php per esempi di questo). Un linguaggio piccolo, con meno funzioni è spesso più facile ragionare, scrivere ed estendere. Per aggiungere una funzionalità è necessario avere una ragione convincente che possa superare il deficit di 100 punti per la complessità aggiuntiva da aggiungere e il costo da pagare.

Non è che questa sia una buona idea, o una cattiva idea ... è solo che ci sono un lotto di buone idee là fuori.

    
risposta data 26.02.2016 - 16:44
fonte
12

Perché questo è un caso d'angolo nella migliore delle ipotesi .

Perché aggiungere complessità alla lingua per qualcosa che poche persone avrebbero mai usato e che userebbe raramente anche allora?

    
risposta data 26.02.2016 - 15:56
fonte
11

In genere non è possibile rispondere alla domanda perché una lingua (in qualsiasi lingua) non supporta una determinata funzione. A meno che la funzione non sia stata esplicitamente considerata e rifiutata dai progettisti di linguaggi, la spiegazione potrebbe benissimo essere che nessuno lo ha mai considerato in primo luogo. La funzione che suggerisci è così oscura che considererei molto probabile che nessuno ci abbia mai pensato seriamente, quindi nessuno ha mai preso la decisione consapevole di non supportarlo.

La funzione sarà difficile da implementare nei linguaggi in stile C, poiché in questi linguaggi un if -statement con più rami è in realtà solo una catena nidificata di semplici istruzioni if / else . La tua proposta richiederebbe una logica di analisi diversa, poiché l'ultimo ramo dovrebbe "conoscere" tutti i rami precedenti.

Inoltre, la semantica non è ovvia. If / else è semplice - basato su una condizione o un ramo è eseguito o l'altro. Ma nel tuo costrutto, una condizione potrebbe significare che i rami due sono eseguiti. Quindi cosa succede se c'è un ritorno nel primo ramo?

Infine, l'utilità è limitata. Evita di scrivere (condition1 and condition2) - ma solo questa combinazione esatta è di tipo speciale. Se hai un if complesso con molti casi, ci sono più combinazioni che potresti voler gestire, ma solo una è speciale. E devi leggere tutte le condizioni di if per chiarire quale sia esattamente il caso "invisibile", quindi non migliora la leggibilità.

Capisco che tu voglia mantenere DRY, ma non penso che sia una violazione di DRY a dichiarare esplicitamente if (condition1 and condition2) , poiché questa particolare combinazione non appare da nessun'altra parte. Non stai ripetendo alcuna informazione. Nel migliore dei casi stai salvando alcune sequenze di tasti, ma non è la stessa di DRY, che riguarda la ripetizione di informazioni, non la ripetizione di sequenze di tasti.

    
risposta data 26.02.2016 - 16:09
fonte
3

Questo potrebbe essere gestito con un booleano

bool isResult4Needed= true;
if (condition1) {
    result1;
} else if (condition2) {
    result2;
} else {
    result3;
    isResult4Needed= false;
}
if (isResult4Needed) {
    result4;
}

Questo costrutto è più flessibile di una funzione linguistica come any , perché gestisce anche tutti gli altri casi come "Voglio fare X se sono andato giù per il ramo ABC o D, ma voglio fare Y se io è andato giù il ramo EFG o H "usando lo stesso identico approccio. L'aggiunta di una lingua dovrebbe essere molto più complicata e probabilmente finirebbe con la stessa quantità di sintassi aggiuntiva.

    
risposta data 26.02.2016 - 16:43
fonte
1

Quindi, fammi riformulare, capisco il tuo caso: Se la condizione 1 o 2, vuoi anche eseguire il risultato 4 giusto?

if condition1{
  result1
  result4
}elseif condition2{
  result2
  result4
}else{
  result3
}

O puoi fare:

if condition1{
  result1
}elseif condition2{
  result2
}else{
  result3
  return
}
result4
    
risposta data 26.02.2016 - 16:10
fonte
1

Ci sono certamente casi di costrutti in linguaggi che sono in qualche modo collegati a questo. Python, in particolare, ha un paio di esempi:

Abbiamo altri blocchi per i loop:

for item in alpha:
    if test(item):
       break
else:
    print "Not Found!"

E il blocco else per le eccezioni:

try:
   something_that_might_fail()
except:
   print "Something went wrong!"
else:
   print "Everything is fine"

Ci sono correlati nel senso che introducono un ulteriore blocco per una struttura di controllo, come quello che stai proponendo. Certamente, ciò che proponi potrebbe essere aggiunto allo stesso modo.

Sulla base dei meriti effettivi della proposta, ritengo che il costrutto non sia sufficientemente flessibile. La tua proposta gestisce questo caso:

if condition1:
   handler1()
   post_handler()
elif condition2:
   handler2()
   post_handler()
else:
   no_handler()

E se volessi farlo:

if condition1:
   pre_handler()
   handler1()
elif condition2:
   pre_handler()
   handler2()
else:
   no_handler()

O forse questo:

if condition1: 
   with transaction():
      handler1()
elif condition2:
   with transaction():
      handler2()
else:
   no_handler()

Quindi la tua proposta sembra gestire alcuni dei casi che potrebbero sorgere. In quanto tale, non sembra fornire molto valore dal punto di vista del design del linguaggio.

Nelle lingue attuali, potrei implementare questa situazione come:

# actually, in my case this part is almost always a lookup, not a list
# of conditions. YMMV.
if condition1:
   handler = handler1
elif condition2:
   handler = handler3
else:
   handler = None

if handler is not None:
   handler()
   post_handler()
else:
   no_handler()

o

for handler in handlers:
    if handler.condition():
       handler.act()
       break
else:
    no_handler()
    
risposta data 26.02.2016 - 17:02
fonte
1

Secondo me, il problema principale con il costrutto come lo hai definito è che stai separando logicamente ciascuno dei blocchi if e else if dal blocco else . Questo probabilmente ha senso quando stai controllando in modo specifico una stringa ed esegui un comando, come questo:

if myString.equals("loadPotatoes") {
  loadPotatoes();
else if myString.equals("firePotatoes") {
  firePotatoes();
any {
  cleanPotatoes(); // whether we load or fire, clean out old potatoes
}
else {
  throw "Did not recognize command " + myString;
}

Ma in questo caso, la somiglianza semantica del confronto String.equals è interamente scelta dal programmatore. In generale, puoi controllare "se il comando è uguale a ecc, altrimenti se database.errorreportingserver.isconnected() , altrimenti se areGUIErrorAlertsEnabled " e così.

Se non altro, questa è una buona ragione per allontanarsi dal ripetere una particolare operazione di codice come String.Equals (come hai detto, ASCIUTTO) a un vero loop riutilizzabile o costrutto dedicato per esso. Ad esempio, nel mio esempio, avresti una mappa string->Action in sola lettura che mostra una relazione tra i nomi dei comandi e una funzione lambda, per la quale esegui una ricerca, quindi esegui quell'azione e poi cleanPotatoes() , oppure quando la la mappa non trova nulla, fa qualcos'altro.

Come altri hanno detto, anche questo è un caso marginale e perché le lingue tendono ad evitare l'aggiunta di parole chiave o regole speciali (potrei vedere questo involontariamente prendere effetto contro un errore di sintassi per ciò che si intende per if/else di base ) la proposta di valore non è elevata.

    
risposta data 26.02.2016 - 21:59
fonte
0

Credo che tu stia cercando di arrivare all'idea di programmazione orientata alle ferrovie . Questo non è molto ben supportato nella maggior parte dei linguaggi orientati agli oggetti, ma puoi farlo aggiungendo un Maybe , Either o Result container.

Ad esempio, se abbiamo quattro funzioni che restituiscono tutte un Maybe o Nothing , puoi fare qualcosa di simile:

if condition1:
  result = functionA()
else if condition2:
  result = functionB()
else:
  result = functionC()

return result.or(defaultValue)
    
risposta data 26.02.2016 - 18:15
fonte

Leggi altre domande sui tag