Devo ignorare le caratteristiche di una lingua quando ho intenzione di eseguire il porting del mio codice su un altro che non ha tali caratteristiche?

5

Attualmente sto giocando con un progetto molto grande. Un interprete per un semplice linguaggio di scripting. Dopo settimane di pianificazione, ho deciso che il miglior modo di agire sarebbe quello di prototipare parte dell'interprete in Python, e quindi portarlo in C.

Ho iniziato scrivendo un semplice lexer basato su un EBNF che avevo scritto, usando Python. Il lexer aveva bisogno di gestire lo stato, quindi ho fatto un uso pesante degli strumenti OOP di Python. Una volta soddisfatto del mio prototipo, ho deciso di provare a portarlo su C.

Python, ovviamente, è orientato agli oggetti e ha classi. Mentre C d'altra parte, non ha un tale concetto. Comincio a chiedermi se dovrei riscrivere il mio lexer. Si era strongmente basato sullo stato fornito dalle classi, ma ovviamente non potevo usare le classi in C.

Così ho iniziato a riscrivere tutto il lexer da zero per utilizzare solo funzioni e variabili globali. Questo ha iniziato a produrre codice un po 'prolisso e difficile da eseguire il debug. Mi sono fermato e mi chiedo se stavo facendo la chiamata giusta. Devo essere costretto a ignorare le caratteristiche di una lingua solo perché la lingua in cui pianifico di consolidare il codice non ha tali funzioni? .

Questo può sembrare un no facile, ma per quanto riguarda il caso in cui un prototipo si basa in gran parte su una determinata caratteristica di un linguaggio (come il mio)? Dovresti davvero passare ore a cercare di compensare la mancanza di tali funzionalità?

Ma il rovescio della medaglia potrebbe altrettanto facilmente essere discusso. Perché dovresti essere costretto a scrivere un codice unidiomatico e dettagliato in una lingua, solo per compensare la mancanza di tali funzionalità in un'altra?

Poiché @MichealDurrant l'aveva richiesto, darò le mie ragioni per usare C:

  • per la velocità
  • Per la portabilità 3
  • Ai fini dell'apprendimento
  • Preferisco la lingua in generale.
  • C sembra essere di fatto la creazione di linguaggi di programmazione. Numerose lingue sono state create in C.
posta Christian Dean 25.11.2016 - 22:15
fonte

5 risposte

7

Sulla base della mia esperienza nella compilazione di compilatori e strumenti correlati in C e lingue simili, NON sceglierei di scrivere un compilatore in C se avessi altre scelte migliori. E nel 2016, ci sono molte scelte migliori. Ma è il tuo compilatore e YMMV.

Il passato di TL; DR:

"We should forget about small efficiencies, say about 97% of the time:
premature optimization is the root of all evil."
                                        — Donald Knuth

Continua dicendo "Eppure non dovremmo perdere le nostre opportunità in quel 3% critico". Supponendo che tu prenda il consiglio del Dr. Knuth in tali questioni (e dovresti davvero), la domanda chiave è quindi: sei in quel 3%?

Sembra dubbio. C può eseguire più velocemente su un codice di basso livello rispetto a qualsiasi altro Python, Perl o PHP. È un ottimo linguaggio di medio livello, eccellente per il rendering del codice strutturato nelle istruzioni della macchina. Per coloro che scrivono compilatori, database e middleware di base, C è una scelta solida. Ma per un linguaggio di scripting? È ancora in sviluppo? Questo ... sembra prematuro.

Nella mia esperienza, Python ha una velocità adeguata anche per il lavoro incentrato sulle prestazioni. Eseguo programmi che analizzano, analizzano e trasformano milioni di record di testo. Se tutto fosse scritto in "Python puro", probabilmente non sarebbe abbastanza veloce. Ma molti compiti: analizzare il testo o l'XML, sfornare cumuli di dati, ecc. - quelli sono quasi sempre gestiti in C già. Moduli come Pandas, NumPy e LXML fanno il loro lavoro pesante al livello più basso e ottimizzato possibile. Python sfrutta le sue ottimizzazioni, ma in un linguaggio molto pulito, standardizzato e di alto livello. Raramente ho trovato il bisogno di andare altrove. Quando ho, ottimizzazioni mirate in C o Cython, con il flusso del programma principale gestito in Python, sono state eccellenti.

Dopo aver osservato tonnellate di C nel corso degli anni (sistemi operativi, compilatori, middleware, applicazioni, utility) e averne scritto alcune, sfido l'idea che C sia particolarmente portatile. È comparato all'era da cui è emerso. Ma erano gli anni '70 e '80. La competizione era quasi del tutto non portatile. C rimane straordinariamente esposto alle differenze nell'ordine dei byte della piattaforma, nella lunghezza delle parole, nella semantica dell'indirizzamento e nelle versioni / versioni dei sistemi operativi. Il codice pensato per eseguire molte piattaforme è spesso disseminato di #ifdef e conoscenza diretta della piattaforma. È brutto. Alla fine, C è non molto portabile rispetto ai linguaggi più moderni come Java, Go, Python e JavaScript.

Quindi se ti piace C, vuoi studiarlo o vuoi lavorare lì, Dio benedica. Ma come già stai scoprendo, non è un ambiente particolarmente favorevole per gli standard moderni. Classi, dizionari, liste flessibili, buona e semplice corrispondenza delle stringhe, strutture dati orientate ai problemi come set e Counter , facile gestione delle eccezioni, strong supporto dei moduli .... L'elenco delle cose preziose che C manca è molto lungo. Potresti essere in grado di recuperare alcune funzioni di livello superiore se utilizzi un framework come Violoncello . Tuttavia, C è il miglior design di 45 anni fa; manca di molti progressi in termini di facilità, flessibilità, robustezza e struttura rispetto a quelli che sono emersi successivamente.

Dovresti valutare i vantaggi della maggiore velocità di esecuzione di C rispetto all'ambiente meno favorevole, i tempi di sviluppo più lunghi, la minore affidabilità probabile e altri fattori. Nel 1970 o 1980, le risorse di sistema erano estremamente rigide, quindi ottimizzare-ottimizzare-ottimizzare aveva senso. In questo giorno di processori multicore e memorie gigabyte anche su smartphone, puoi legittimamente considerare l'ottimizzazione di attributi diversi dalle prestazioni. Time-to-market, sofisticatezza del programma, affidabilità, manutenibilità - ci sono molte cose che puoi ragionevolmente ottimizzare in Python (o in un altro linguaggio di alto livello) che non puoi facilmente ottimizzare in C.

    
risposta data 26.11.2016 - 04:04
fonte
7

Ignorare le caratteristiche in questo caso non ha senso per me.

Il motivo tipico per usare Python per la prototipazione è esattamente perché puoi implementare le cose in una frazione di tempo e "spazio" (= linee di codice) rispetto a C - usando le funzionalità che ha Python, ma C no. Se ti limitassi solo alle funzionalità di Python che hanno una corrispondenza 1: 1 con una caratteristica C, usare Python di prima mano non avrebbe più senso: potresti implementare il tuo programma in C fin dall'inizio.

A proposito, hai considerato Cython per il tuo caso d'uso?

    
risposta data 26.11.2016 - 00:06
fonte
3

Qualsiasi funzione linguistica di Turing-Complete può essere implementata in qualsiasi altra lingua di Turing-Complete. Se così non fosse, saremmo ancora bloccati con il primo linguaggio di programmazione mai inventato. Quindi, in realtà, dipende da quanta fatica vuoi spendere.

In un certo senso, stai facendo la domanda sbagliata. La domanda non è "Devo implementare una funzionalità nella lingua di destinazione se non esiste nella lingua di partenza.La domanda dovrebbe essere" La mia lingua di partenza ha un'espressività sufficiente per implementare facilmente le funzionalità che desidero nella mia lingua di arrivo? "

In altre parole, non hai bisogno dell'orientamento agli oggetti nella tua lingua di origine per implementarlo con successo nella tua lingua di destinazione.

C è una scelta naturale per interpreti di lingua e compilatori. La sua relativa semplicità lo rende in realtà ideale per l'implementazione di altri linguaggi, perché ha relativamente pochi paradigmi elaborati in esso, e quindi non ti inserisce nelle sue scelte progettuali.

Inoltre, C è un buon target per un Intermediate Language da compilare; poiché è multipiattaforma, puoi compilare il codice risultante in un binario quasi ovunque.

    
risposta data 25.11.2016 - 22:51
fonte
2

Il bootstrap del compilatore è sempre difficile. Una volta ho scritto un compilatore Modula2 per un IBM / 370. Il compilatore è arrivato in Modula2. Quindi ero nella situazione del barone Muenchhausen che si è tirato fuori dalla palude con i suoi capelli. Il modo in cui l'ho fatto è stato in primo luogo scrivere un cross-compiler da Modula2 a PascalVS che sono molto simili (entrambi sono figli di Wirth). Quindi sono stato in grado di compilare il compilatore. Di conseguenza il compilatore ha prodotto un codice M che poteva essere eseguito con un interprete che veniva fornito con il compilatore Modula2. Veeery lento, ma funzionante. Quindi l'ultima parte è scrivere un generatore di codice per l'assemblatore.

Ora, cosa si può imparare da questo? Vedi la risposta di Robert. Scrivere un compilatore direttamente in C potrebbe non essere "intelligente" ma ti fa risparmiare un sacco di lavoro.

    
risposta data 26.11.2016 - 00:03
fonte
2

Hai scritto il tuo programma Python per provare un concetto , ho capito - penso che sia perfettamente eccellente e ammirevole.

Il tuo piano è stato, dall'inizio alla fine implementare anche in C. Fine, ma ritengo anche che tu voglia la velocità e l'efficacia di quel linguaggio (anche se troverai molte persone chi sarebbe disposto a discutere sui vantaggi tra C e Python, ma non è questo il punto qui.

Allora dici, tuttavia, hai porting la dimostrazione del concetto in C - Penso che generalmente sia il modo sbagliato di guardarlo. Una dimostrazione del concetto in un'altra lingua non dovrebbe essere ported - L'implementazione dovrebbe essere un'implementazione da zero e utilizzare il concetto che hai provato , non il programma che usato per farlo - spero che tu veda la differenza. Immagino che sarebbe molto meglio "dimenticare" completamente la tua implementazione Python prima ancora di provare a implementare in C.

    
risposta data 26.11.2016 - 11:50
fonte