Nei linguaggi di programmazione, COMEFROM (o COME FROM) è una oscura struttura di controllo usata in alcuni linguaggi di programmazione, originariamente pensata come uno scherzo.
COMEFROM
è a grandi linee l'opposto di GOTO
in quanto può acquisire lo stato di esecuzione da un punto arbitrario del codice verso una istruzione COMEFROM
. Il punto del codice dal quale lo stato attivo viene trasferito è usualmente passato come parametro di COMEFROM
. Il fatto che il trasferimento avvenga prima o dopo l'istruzione indicata al punto di origine dipende dal linguaggio utilizzato. Sempre dipendente dal linguaggio, la possibilità di riferire più istruzioni COMEFROM
alla stessa origine nel codice può risultare non valida, essere non deterministica, richiamare i vari punti del codice in sequenza o avviare processi in parallelo o concorrente.
Un semplice esempio di istruzione "COMEFROM x
" prevede l'utilizzo di un'etichetta, posizionata in un punto del codice altro rispetto al relativo COMEFROM
, che agisce come una sorta di "trappola". Quando l'esecuzione del codice raggiunge l'etichetta, l'esecuzione si trasferisce all'istruzione successiva al COMEFROM
. L'effetto principale è di rendere il debugging (e la compressione del flusso del software) estremamente difficile, dato che non c'è alcuna indicazione in prossimità dell'etichetta che l'esecuzione misteriosamente possa saltare da un'altra parte del programma.
COMEFROM
è stato inizialmente visto in una lista di scherzi in diverse istruzioni assembly (come 'CMFRM'). È stato analizzato in un articolo pubblicato su Datamation da R. Lawrence Clark nel 1973,[1] scritto in risposta alla lettera di Edsger Dijkstra Go To Statement Considered Harmful. COMEFROM è stata implementata nella variante C-INTERCAL del Linguaggio di programmazione esoterico INTERCAL insieme al più misterioso 'COMEFROM
'.
Il 1º aprile 2004, Richie Hindle ha pubblicato un'implementazione delle istruzioni GOTO
e COMEFROM
per Python.[2] Nonostante sia stato distribuito come pesce d'aprile e non pensato per un utilizzo reale, la sintassi è valida e l'implementazione è completamente funzionante.
Seppure COMEFROM
è sintatticamente e semanticamente un comando valido, e potenzialmente in grado di rimpiazzare GOTO
in alcuni programmi, è molto più difficile gestirlo in fase di progettazione e di sviluppo in un linguaggio di programmazione. L'utilizzo più diffuso di costrutti simili a COMEFROM
è l'impostazione di breakpoint in fase di debug. Un'implementazione del FORTRAN ha previsto l'istruzione COMEFROM
, con il nome di "AT
", come aiuto al debug, con evidenti avvisi che ne sconsigliavano l'utilizzo in codice di produzione. In più, molte moderne CPU hanno un supporto hardware per i breakpoint.
Alcuni elementi di Programmazione orientata agli aspetti sono stati paragonati alle istruzioni COMEFROM
.[3]
Nei compilatori che usano SSA, un nodo phi è sostanzialmente simile ad un comando COMEFROM
. Elenca da quali basic block l'attuale basic block avrebbe potuto essere raggiunto e il valore associato da usare per farlo.
Il codice di seguito è un esempio di programma in un ipotetico dialetto BASIC con l'utilizzo di "COMEFROM
" al posto di "GOTO
".
10 COMEFROM 40
20 INPUT "WHAT IS YOUR NAME? "; A$
30 PRINT "HELLO, "; A$
40 REM
Il programma ipoteticamente richiede all'utente il suo nome per poi salutarlo, e ripetere l'operazione all'infinito. L'istruzione "REM
" alla linea 40 è semplicemente un comando di tipo NOP — l'istruzione "COMEFROM
" alla linea 10 richiama l'esecuzione di quella riga quando viene raggiunta la linea 40, indipendentemente dal suo contenuto.
Un divertente esempio eseguibile in Python con il modulo/scherzo goto
installato (che usa il debugger per controllare l'esecuzione del programma) risulterebbe così:
from goto import comefrom, label
comefrom .repeat
name = raw_input('what is your name? ')
if name:
print "Hello",name
label .repeat
print "Goodbye!"
Questa è un'implementazione in Ruby dell'istruzione COME FROM in Interical.
$come_from_labels = {}
def label(l)
if $come_from_labels[l]
$come_from_labels[l].call
end
end
def come_from(l)
callcc do |block|
$come_from_labels[l] = block
end
end
Alcuni esempio delle funzionalità di debug del compilatore Fortran OS/360:[4]
Example 1:
INTEGER SOLON, GFAR, EWELL
.
.
.
10 SOLON = GFAR * SQRT(FLOAT(EWELL))
11 IF (SOLON) 40, 50, 60
.
.
.
DEBUG UNIT(3)
AT 11
DISPLAY GFAR, SOLON, EWELL
END
Example 2:
DIMENSION STOCK(1000),OUT(1000)
.
.
.
DO 30 I=1, 1000
25 STOCK(I)=STOCK(I) - OUT(I)
30 CONTINUE
35 A = B + C
.
.
.
DEBUG UNIT(3)
AT 35
DISPLAY STOCK
END
Example 3:
10 A = 1.5
12 L = 1
15 B = A + 1.5
20 DO 22 I = 1,5
.
.
.
22 CONTINUE
25 C = B + 3.16
30 D = C/2
STOP
.
.
.
DEBUG UNIT(3), TRACE
C DEBUG PACKET NUMBER 1
AT 10
TRACE ON
C DEBUG PACKET NUMBER 2
AT 20
TRACE OFF
DO 35 I = 1,3
.
.
.
35 CONTINUE
TRACE ON
C DEBUG PACKET NUMBER 3
AT 30
TRACE OFF
END
Nell'esempio 1, i valori di SOLON, GFAR, ed EWELL sono esaminati dopo il completamente dell'istruzione 10. L'istruzione AT rinvia alla riga 11.
Nell'esempio 2, tutti i valori di STOCK sono visualizzati quando viene eseguita la riga 35.
Nell'esempio 3, il TRACE viene eseguito dalla riga 10 alla riga 20. Il tracing viene interrotto durante l'esecuzione del loop e riattivato successivamente. Il tracing viene interrotto definitivamente durante l'esecuzione dell'istruzione alla riga 30.
Il DSP del computer SHARC supporta un'istruzione DO..UNTIL
, pensata per l'implementazione di cicli di tipo Do While, ma che sono essenzialmente istruzioni COMEFROM
. Un esempio:
LCNTR=42; DO x UNTIL LCE; /* COMEFROM x, unless the loop counter is zero */ F12=F0*F4, F8=F8+F12, F0=dm(I0,M3), F4=pm(I8,M9); IF NZ dm(I2,M2) = F12; IF ZF dm(I2,M2) = F1; x: R2 = R3 + 76; /* the label "x" does not exist in the machine code */
È da notare che la condizione per il termine del loop, qui indicata come LCE
(loop counter expired), può essere impostata su altri valori, incluso sempre vero o sempre falsa. Con una condizione sempre vera, si realizza nella pratica un'istruzione di tipo COMEFROM
. L'hardware supporta fino a sei COMEFROM
attivi simultaneamente.