Quando le persone dicono che "X non compone", ciò che intendono per "comporre" significa in realtà "mettere insieme", e cosa e come li metti insieme può essere molto diverso, a seconda di cosa sia esattamente "X".
Inoltre, quando dicono "non comporre", possono significare alcune cose leggermente diverse:
- Non puoi mettere insieme due X, punto.
- È possibile mettere due Xs insieme, ma il risultato potrebbe non essere una X (IOW: X non è chiuso sotto la composizione .)
- Puoi mettere insieme due X, ma la X risultante potrebbe non funzionare come previsto.
Un esempio per il n. 1 sono i parser con scanner / lexer. Potresti sentire la frase "scanner / lexer non compongono". Questo non è in realtà vero. Ciò che intendono è "il parser che utilizza una fase di lexing separata non compone".
Perché dovresti voler comporre parser? Bene, immagina di essere un fornitore IDE come JetBrains, Eclipse Foundation, Microsoft o Embarcadero e vuoi creare un IDE per un framework web. Nello sviluppo web tipico, mescoliamo spesso le lingue. Hai file HTML con <script>
elementi contenenti ECMAScript e<style>
elementi contenenti CSS. Sono disponibili file modello contenenti HTML, alcuni linguaggi di programmazione e alcune metasintassi del linguaggio dei modelli. Non vuoi scrivere diversi evidenziatori di sintassi per "Python", "Python incorporato in un modello", "CSS", "CSS in HTML", "ECMASCript", "ECMAScript in HTML", "HTML", "HTML entro un modello ", e così via e così via. Si desidera scrivere un evidenziatore di sintassi per Python, uno per HTML, uno per il linguaggio modello e quindi comporre i tre in un evidenziatore di sintassi per un file modello.
Tuttavia, un lexer analizza l'intero file in un flusso di token, il che ha senso solo per quella lingua. Il parser per l'altra lingua non può funzionare con i token che il lexer gli passa. Ad esempio, i parser Python sono in genere scritti in modo tale che il lexer tenga traccia dell'indentazione e inietti falsi INDENT
e DEDENT
token nel flusso di token, consentendo così al parser di essere privo di contesto, anche se in realtà la sintassi di Python non lo è. Un lexer HTML tuttavia ignorerà completamente gli spazi bianchi, poiché non ha alcun significato in HTML.
Un parser senza scanner, tuttavia, che legge semplicemente i caratteri, può passare il flusso di caratteri a un altro parser, che può quindi restituirlo, rendendoli così molto più facili da comporre.
Un esempio per # 2 sono le stringhe con query SQL al loro interno. È possibile avere due stringhe, ognuna delle quali contiene una query SQL sintatticamente corretta, ma se si concatenano le due stringhe, il risultato potrebbe non essere una query SQL sintatticamente corretta. È per questo che abbiamo di query algebre come ARel
, che fanno di composizione.
I blocchi sono un esempio di # 3. Se hai due programmi con blocchi e li combini in un singolo programma, hai ancora un programma con blocchi, ma anche se i due programmi originali erano completamente corretti, privi di deadlock e razze, il programma risultante non ha necessariamente questo proprietà. L'uso corretto dei blocchi è una proprietà globale dell'intero programma e una proprietà che non viene preservata quando si compongono i programmi. Questo è diverso da, per esempio, le transazioni, che fanno di composizione. Un programma che utilizza correttamente le transazioni può essere composto con un altro programma simile e produrrà un programma combinato che utilizza correttamente le transazioni.