Funzionamento interno della funzione IF () - perché non vengono valutate le espressioni?

5

Versione breve

In che modo la funzione IF() fa sì che le espressioni passate NON vengano valutate prima di essere passate come parametri?

Versione dettagliata

Faccio parte di un comitato per gli standard e ho avviato una discussione che, in generale, sta cercando di vietare l'uso della funzione IIF() . Il consenso generale è che se si desidera eseguire un breve incarico IF() va bene. E se per qualche ragione vuoi valutare due espressioni, non provare a realizzare tutto ciò su una riga, valuta in modo esplicito e mirato le espressioni su linee separate, quindi fai una chiamata IF() con restituisce i parametri If True e If Else .

Sto affermando che prima che un Function(param1, expression) venga inserito, qualsiasi espressione viene valutata. Quindi, il loro valore valutato viene passato come parametro.

Affermato, questo ha senso:

Sub Main()
    Dim intTest As Integer = 0
    Dim blnResult As Boolean = IIf(2 = 2, Integer.TryParse("3", intTest), Integer.TryParse("4", intTest))
    'intTest = 4
End Sub
  • Come previsto, blnResult è True .
  • Poiché il condizionale della funzione IIF() è True , il valore dell'espressione nel parametro "If True" è il compito risultante.
  • Ma ENTRAMBI le espressioni If True AND If Else sono state valutate (in ordine scritto) prima di passare anche al IIF() funzione, quindi intTest è diventato 4 .
  • Per quanto mi riguarda, ciò è programmaticamente previsto, ma non i risultati desiderati.

Sul retro della moneta, abbiamo questo:

Sub Main()
    Dim intTest As Integer = 0
    Dim blnResult As Boolean = If(2 = 2, Integer.TryParse("3", intTest), Integer.TryParse("4", intTest))
    'intTest = 3
End Sub

Come l'inverso del problema precedente, ora abbiamo:

  • Come previsto, blnResult è True.
  • Poiché il condizionale della funzione IF() è True , il valore dell'espressione nel parametro "If True" è il compito risultante.
  • Ma SOLO viene valutato il If True (in questo caso), quindi intTest diventa 3 .
  • Per quanto mi riguarda, questo è il risultato desiderato, ma non previsto in modo programmatico.

Mi piacerebbe vedere una funzione personalizzata che faccia la stessa cosa di IF() .

    
posta Suamere 15.08.2013 - 23:14
fonte

5 risposte

6

La tua confusione deriva da un malinteso:

Inner Workings of the IF() Function

How does the IF() Function

the conditional of the IF() Function

I'd like to see a custom function that does the same thing as IF()

Ma IF() non è una funzione.

La specifica della lingua per VB.NET (disponibile gratuitamente per il download) ha questo da dire circa If . Cito la versione 11.0; sottolinea come il mio, e nota che l'errore apparente nell'esempio è una citazione diretta!:

11.22 Conditional Expressions

A conditional If expression tests an expression and returns a value. Unlike the IIF runtime function, however, a conditional expression only evaluates its operands if necessary. Thus, for example, the expression If(c Is Nothing, c.Name, "Unknown") will not throw an exception if the value of c is Nothing.

Nota la differenza: If è un'espressione , mentre IIf è una funzione . Come qualsiasi altra funzione, IIf obbedisce alle consuete regole di valutazione dei parametri. Ma If , essendo un'espressione , non deve.

Non ti aspetteresti

If <condition> Then
    ' Do this
Else
    ' Do that
End If

per eseguire sia this che that ; allo stesso modo, non dovresti aspettarti If per valutare entrambe le parti.

Non sarai in grado di fare prontamente una funzione che fa questo, non più di quanto tu possa essere in grado di dire una funzione che fa Using - fa parte di lingua .

    
risposta data 16.08.2013 - 10:35
fonte
3

IF() è trattato come caso speciale dal compilatore. Non è possibile creare una propria funzione che funzioni esattamente allo stesso modo senza creare il proprio compilatore. Potresti usare delegati o espressioni lambda con effetti simili, però.

    
risposta data 16.08.2013 - 00:16
fonte
3

In pratica stai descrivendo la valutazione del cortocircuito.

Non vedo il problema che descrivi come fondamentalmente diverso dalla differenza tra And e AndAlso . Se hai intenzione di escludere IIF , devi anche mettere al bando And , poiché non cortocircuita entrambi (entrambi gli operandi sono sempre valutati).

Bascere costrutti linguistici che non siano in cortocircuito potrebbe avere più senso se anche richiedono che le tue funzioni non abbiano mai effetti collaterali. Se permetti effetti collaterali nelle tue funzioni, quegli effetti collaterali non si verificano se sono nella parte cortocircuitata di una valutazione di funzione.

Ulteriori letture
Perché una lingua NON usa la valutazione del cortocircuito?

    
risposta data 16.08.2013 - 01:59
fonte
1

VB.NET ha un operatore che svolge la doppia funzione sia degli operatori ternari che a coalescenza nulla. Questo operatore è If. Ha anche una funzione, IIF, che accetta tre parametri.

Queste sono due cose completamente diverse. La funzione IIF è proprio questo, una funzione, potresti scrivere la tua che fa esattamente la stessa cosa. Dovrebbe essere evitato, è diventato obsoleto nel momento in cui l'operatore è stato introdotto.

Ora, l'operatore IF è abbastanza maneggevole e consente di fare cose che sarebbe stato estremamente difficile persino approssimativo, e impossibile esattamente duplicare, prima di lambdas sono stati introdotti (non è ancora possibile duplicarlo esattamente, ma potresti ottenere un effetto simile). Non c'è motivo di evitarlo, si comporta come previsto, quindi anche se non lo sai, non sorprende, quindi non è un pericolo per i programmatori junior.

Entrambe le funzioni dell'operatore If sono fondamentalmente dei calcoli di cortocircuito, ed è una buona cosa.

Se lo standard su cui stai lavorando è per l'uso di VB.NET, allora dovrebbe essere raccomandato. Se è per una nuova lingua, raccomando entrambi gli operatori come utili aggiunte a programmi leggibili e comprensibili (potresti voler renderli un po 'più distinti).

PS: tu dici che l'IIF si comporta come previsto, io lo negherei e cambierei un po 'il tuo esempio:

 Dim input as String = "Junior"
 Dim parsed as Integer
 parsed = IIF(IsNumeric(parsed), CInt(input), -1)

Getta questo a qualcuno che non ha familiarità con la lingua e naturalmente si aspettano che sia parsato -1. Il che non è ciò che accade, ma ottieni un'eccezione di cast non valida. link

Ho corretto bug esattamente come sopra.

    
risposta data 16.08.2013 - 05:55
fonte
0

Risposta tecnica:

Sappiamo tutti che la funzione If() è "l'operatore ternario per VB.NET ", mentre IIF() è una funzione (anche se ancora tecnicamente ternaria). Ma dire che If () è "l'operatore ternario" non significa che sappiamo cosa sta succedendo dietro le quinte. Bene, si scopre letteralmente che cosa sta succedendo dietro le quinte è che la funzione If () viene valutata come un'espressione che è interpretata da Common Intermediate Lingua (CIL) come operatore ternario C-esque, come mostrato nel CIL di seguito:

bool arg_20_0 = true ? int.TryParse("3", out intTest) : int.TryParse("4", out intTest);

Descrizione:

Come parte delle risposte precedenti, è stato rilevato che il compilatore probabilmente interpreta la funzione IF () come espressione invece di IF () in realtà è una funzione regolare. È parzialmente vero.

È stato anche sollevato il fatto che se si vietasse IIF (), si vietavano anche cose come And e Or sul posto per il codice di solo cortocircuito. Era molto più vicino alla risposta reale di quanto mi aspettassi all'inizio.

Come semplice test a cui sono emberrassed non ho provato prima, dato che ho ILSpy sul mio desktop e lo uso tutto il tempo, ho trovato che la vera risposta era il primo commento ... MichaelT ha chiesto:

Just verifying, the IFF(A,B,C) is equivalent to A?B:C in a C-esque language?

LAWL !!! Questo è il codice CIL:

bool arg_20_0 = true ? int.TryParse("3", out intTest) : int.TryParse("4", out intTest);

Quindi è parzialmente vero che IF () non è una funzione reale, ma è valutata nel CIL prima di andare al compilatore, quindi non è una funzione di creazione del proprio compilatore. Darò credito a MichaelT se pubblicherà questo come sua risposta, era corretto al 100% senza nemmeno saperlo.

Modifica (aggiunta):

Come affermato nel commento, ho detto che avrei pubblicato il CIL per IIF (). Questo è ...

bool blnResult = Conversions.ToBoolean(Interaction.IIf(true, int.TryParse("3", out intTest), int.TryParse("4", out intTest)));

Che è esattamente come previsto, perché l'IIF è una funzione reale, quindi ovviamente i parametri vengono valutati prima di entrare nella funzione. Sapevo anche che era nello spazio dei nomi di Interaction. Ma come ho detto, IIF () non è il mistero, è capito, ma solo i risultati attesi.

    
risposta data 16.08.2013 - 04:20
fonte

Leggi altre domande sui tag