Le strutture di dati dovrebbero essere integrate nel linguaggio (come in Python) o essere fornite nella libreria standard (come in Java)?


21

In Python, e molto probabilmente in molti altri linguaggi di programmazione, è possibile trovare strutture di dati comuni come parte integrata del linguaggio principale con la propria sintassi dedicata. Se mettiamo da parte la sintassi dell'elenco integrato di LISP, non riesco a pensare ad altre lingue che conosco che forniscono una sorta di struttura di dati sopra l'array come parte integrante della loro sintassi, sebbene tutte (ma C, immagino) sembrano fornirli nella libreria standard.

Dal punto di vista della progettazione linguistica, quali sono le tue opinioni sull'avere una sintassi specifica per le strutture di dati nella lingua principale? È una buona idea e lo scopo della lingua (ecc.) Cambia quanto potrebbe essere utile questa scelta?

Modifica: mi dispiace per (apparentemente) causare confusione su quali strutture di dati intendo. Parlo di quelli di base e di uso comune, ma non ancora di quelli di base. Ciò esclude alberi (troppo complessi, non comuni), pile (usati troppo di rado), matrici (troppo semplici) ma include ad esempio set, elenchi e hashmap.


1
Stiamo escludendo l'oggetto e l'hashmap?
Orbling

3
@Anto: Beh, molte lingue hanno hashaps sotto forma di array associativi, Perl, PHP, JS (tecnicamente un oggetto qui), ecc.
Orbling

1
Forse potresti essere più specifico su quali strutture di dati stai pensando, a parte matrici, elenchi, hashaps / matrici associative?
FrustratedWithFormsDesigner,

1
Includi hashaps, elenchi e tutto ciò che è più avanzato come "strutture di dati complessi" e lancia array come troppo semplici.
Anto

1
Penso che un titolo più sensato sarebbe qualcosa del tipo: "Quali strutture di dati dovrebbero essere incluse nella lingua e cosa nella biblioteca?" Una risposta significativa dipende in larga parte dalla lingua: più la biblioteca è integrata nella lingua in modo pulito, più è ragionevole spostare le strutture nella biblioteca.
Jerry Coffin,

Risposte:


13

Dipende a cosa serve la lingua.

Alcuni esempi (un po 'rubati da altre risposte):

  • Perl ha una sintassi speciale per hashtable, array, stringhe. Perl è spesso usato per gli script, questi sono utili per gli script.
  • Matlab ha una sintassi speciale per elenchi, matrici, strutture. Matlab è per fare matematica a matrice e vettoriale per ingegneria.
  • Stringa e array di supporto Java / .NET. Si tratta di linguaggi generici in cui vengono spesso utilizzate matrici e stringhe (sempre meno con l'uso di nuove classi di raccolta)
  • Array di supporto C / C ++. Queste sono lingue che non ti nascondono l'hardware. Le stringhe sono parzialmente supportate (nessuna concatenazione, usa strcpy, ecc.)

Penso che dipenda dallo scopo / spirito / pubblico della tua lingua; quanto astratto e quanto lontano dall'hardware vuoi che sia. Generalmente le lingue che supportano gli elenchi come primitive consentono di creare elenchi infinitamente lunghi. Sebbene un livello basso come C / C ++ non li abbia mai, perché non è questo l'obiettivo, lo spirito di quelle lingue.

Per me, la garbage collection segue la stessa logica: il pubblico della tua lingua si preoccupa di sapere esattamente quando e se la memoria viene allocata o liberata? Se sì, malloc / free; se no, quindi garbage collection.


6
Questo è un brutto posto per usare il termine "C / C ++", perché la presenza di tipi di template di alto livello in C ++ è una grande differenza tra i due linguaggi.
dan04,

La raccolta dei rifiuti può essere fatta in modo deterministico, hai solo bisogno di tipi lineari (o il loro sostituto del loro povero: RAII).
pyon,

@ EduardoLeón, anche se puoi chiamare la garbage collection in un punto deterministico, non penso per quanto tempo durerà è deterministico (per lo stesso motivo malloce newnon deterministico in C / C ++).
EarlNameless

@earlNameless: è deterministico rispetto all'uso della risorsa: i tipi lineari (o tipi di unicità, che sono simili) rendono un errore di tipo (e, quindi, errore di compilazione) non liberare risorse (modulo la possibilità, non catturato dal tipo sistema, di qualsiasi chiusura anomala del programma) o di utilizzarli dopo che sono stati eliminati.
pyon,

5

Perl ha hashmaps e PL / SQL supporta i record, e ho ricordi molto nebbiosi di matlab con sintassi per supportare vettori e matrici di tutte le diverse dimensioni (anche se potrei sbagliarmi su questo e si potrebbe sostenere che questi sono tipi di dati non dati strutture ) ... Direi che avere un supporto nativo per strutture molto comuni è bello avere. Di solito sembra che gli array e gli hashm / array associativi siano le strutture supportate nativamente più comuni, e probabilmente sono anche le più comunemente usate.

Non dimenticare che se aggiungi il supporto della sintassi nativa per altre strutture come gli alberi binari, tali strutture sono anche implementate dagli strumenti di supporto del linguaggio (compilatore / runtime / ecc.). Per quante strutture vuoi creare supporto?

Dovrai inventare una nuova notazione per le strutture supportate meno comunemente in modo nativo ... Keep It Simple !.


Non è necessario inventare una sintassi letterale ad esempio per gli alberi: sono più rari, non sono nemmeno nella lingua di molte lingue! Con lo stesso argomento, si potrebbe opporsi all'inclusione degli operatori perché "dovresti inventare una nuova notazione per le operazioni meno comunemente utilizzate".

@delnan: Il modo in cui l'ho capito era dal punto di vista della progettazione di un nuovo linguaggio e mi chiedevo se le strutture di dati oltre alle matrici dovessero essere supportate nativamente da (eventualmente) una nuova sintassi o se dovrebbero essere supportate includendo una libreria.
FrustratedWithFormsDesigner

Bene, la prima frase parla esplicitamente di "strutture di dati comuni", quindi presumo che OP non sia abbastanza folle da provare ad aggiungere una sintassi speciale per ogni oscura struttura di dati mai inventata.

@delnan: ... e poi l'OP continua ad escludere elenchi e array LISP (in generale) "... mettere da parte la sintassi dell'elenco integrato di LISP, non riesco a pensare ad altre lingue che conosco che forniscano un qualche tipo di struttura dei dati sopra l'array come parte integrante della loro sintassi "... quindi ho pensato che stessero riflettendo su strutture di dati più esotiche di array / elenchi ...
FrustratedWithFormsDesigner

Sì (ho interpretato "sopra le matrici" come "altre strutture di dati comuni"), ma nulla nella domanda suggerisce "facciamo dei letterali per ogni singola struttura di dati che abbiamo". Va bene affermare che questo dovrebbe essere limitato a ciò che è ragionevole, ma non credo che possiamo dire "cattiva idea" solo per questo presupposto .

5

Il mio esempio preferito qui è Lua . Lua ha solo un tipo di dati incorporato, la " tabella ", ma la sua flessibilità e velocità significano che in realtà li usi al posto di matrici regolari, elenchi collegati, code, mappe e sono persino la base per le funzionalità orientate agli oggetti di Lua (es. classi).

Lua è un linguaggio incredibilmente semplice, ma la flessibilità della struttura dei dati della tabella lo rende anche abbastanza potente.


2
Gli oggetti JavaScript sono davvero allo stesso modo: le matrici sono solo oggetti con proprietà numeriche e lunghezza, ad esempio.
Tikhon Jelvis,

1
Le tabelle Lua sono diverse dagli oggetti JavaScript: in JavaScript {}no [], in Lua hai {}entrambe le cose. Le tabelle Lua si confrontano meglio con le liste in Lisp.
Jakob,

Immagino che in JavaScript "tutto sia un oggetto" - compresi gli array - ma non tutto è un array. In Lua, tutto è un tavolo.
Dean Harding,

3

Non è necessario disporre di una sintassi dedicata per ogni tipo di dati di alto livello. Ad esempio, è tollerabile avere set([1, 2, 3])(come ha fatto Python 2.x) invece di {1, 2, 3}.

L'importante è avere un modo conveniente per costruire una struttura di dati di alto livello. Quello che vuoi evitare è un codice come:

s = set()
s.add(1)
s.add(2)
s.add(3)

che mi infastidisce enormemente quando uso std::vector, std::sete std::mapin C ++. Per fortuna, il nuovo standard avrà std::initializer_list.


3

A mio avviso, è un'aggiunta incredibilmente semplice che può tornare utile sorprendentemente spesso, almeno se eseguita con cautela - vale a dire al massimo per tuple, elenchi, mappe e set in quanto quelli hanno letterali ben noti.

  • È economico da aggiungere a una lingua. Non ti costa molto di quel prezioso budget di complessità:
    • la grammatica è fondamentalmente someBracket {expr ','} someBracketo someBracket {expr ':' expr ','} someBracket, con alcuni extra semplici morti se vuoi cose come virgole finali opzionali. I letterali float possono essere facilmente più lunghi in grammatica.
    • In molte lingue, nessuno dei letterali popolari si scontra con la sintassi esistente (un'eccezione che mi viene in mente è una lingua con blocchi simili a parentesi graffe come espressioni, un operatore virgola e nessun punto e virgola, come in {1, 2})
    • La semantica può essere definita in meno di cinque frasi, la versione informale è "Crea un'istanza di una nuova raccolta $, quindi chiama .add/ .append/ .setItemuna volta per determinate espressioni con quella (quelle) espressione (e) come argomenti".
  • Grazie al terzo punto precedente, è anche molto facile da implementare.
  • È incredibilmente utile quando ne hai bisogno e non ha (è necessario) influire sulla sintassi di altri elementi, cioè non "paghi" per esso quando non lo usi.

3

Clojure è un pò ma supporta

Lists: (x1 x2)
Vectors: [x1 x2]
Maps: {k1 v1 k2 v2}
Sets: #{x1 x2}

2

Più strutture di dati hai nella lingua stessa, più difficile sarà la lingua da imparare. Potrebbe essere una preferenza personale, ma tendo a preferire un linguaggio più semplice e quindi eventuali extra possono essere forniti dalle biblioteche.

Le lingue progettate per campi specifici possono talvolta trarre vantaggio dall'avere determinate strutture di dati integrate nella lingua come Matlab. Ma troppi possono sopraffarti.


2

Affinché una lingua sia davvero utile, deve svolgere un certo grado di compiti fuori dalla scatola. Perché la pratica programmazione quotidiana richiede strumenti che risolvano i loro problemi a un livello generico. Il minimalismo appare compatto e interessante, ma quando vuoi iniziare a utilizzare per risolvere problemi grandi ma ripetuti, hai bisogno di un livello di astrazione su cui puoi costruire.

Quindi penso che i linguaggi di programmazione dovrebbero fornire supporto per le strutture di dati più comunemente utilizzate nella sintassi per i compiti per cui il linguaggio è progettato.


2

In generale trovo conveniente avere letterali per elenchi, set e così via. Ma a volte mi dà fastidio il fatto che io non sappia nulla dell'implementazione effettiva - diciamo - dell'elenco Python o dell'array Javascript. L'unica cosa di cui posso essere sicuro è che espongono una determinata interfaccia.

Prendo come punto di riferimento di una espressività del linguaggio quanto bene può scrivere le proprie strutture di dati come librerie e quanto sia conveniente usarle.

Ad esempio, Scala offre varie collezioni con diverse garanzie di implementazione e prestazioni. Tutti sono implementati in Scala stessa e la sintassi per usarli è solo leggermente più complessa rispetto a se fossero incorporati e avessero il supporto di runtime.

L'unica struttura di base che ha davvero bisogno del supporto del runtime stesso, almeno in una lingua gestita, è l'array: se non gestisci la memoria, avrai difficoltà a ottenere un mucchio di byte adiacenti. Ogni altra struttura può essere costruita da matrici e puntatori (o riferimenti).


1

APL (e relative varianti moderne, A +, J e K) hanno strutture scalari, vettoriali e matriciali come strutture di dati di prima classe.

Sì, possono essere deprecati come semplici varianti sull'array. Ma sono anche liberi da dichiarazioni complesse e non provengono da una libreria separata, si sentono come strutture dati complesse che sono una parte di prima classe del linguaggio.


APL ha anche matrici nidificate e le matrici non devono avere un tipo di dati omogeneo, il che rende tutte strutture di dati molto potenti.
RFlack,

1

Dal punto di vista della progettazione linguistica, quali sono le tue opinioni sull'avere una sintassi specifica per le strutture di dati nella lingua principale? È una buona idea e lo scopo della lingua (ecc.) Cambia quanto potrebbe essere utile questa scelta?

I letterali di elenchi e mappe e una comoda sintassi di chiusura sono caratteristiche essenziali delle lingue di alto livello.

La differenza tra questo codice Java:

Thing t = new Thing();
t.setFoo(3);
t.setBar(6.3);
t.setBaz(true);

e questo codice Groovy:

t = new Thing(foo: 3, bar: 6.3, baz: true)

è enorme. È la differenza tra un programma da 40.000 linee e un programma da 10.000 linee. La sintassi è importante.


In C # si possono fare: var t = new Thing(foo: 3, bar: 6.3, baz: true);- solo altri 4 caratteri.
Giobbe

è in realtà lo stesso numero; il codice Groovy dovrebbe leggere 'def t = ...'
kevin cline

1

Certo, dipende dall'applicazione del linguaggio di programmazione, ma per linguaggi di livello superiore dovrebbe essere il più conveniente possibile lavorare con qualsiasi struttura di dati comune. Dai un'occhiata all'elenco dei tipi di dati astratti in Wikipedia per esempi. Ho trovato i seguenti principi di base più comuni (ma mi piacerebbe anche ascoltare altre opinioni):

  • sequenze ordinate (monodimensionali): array, coda, stack, elenchi ...
  • strutture multidimensionali ordinate : tabella, vettore, matrice ..
  • mappe : hashmap, dizionario, set, multimap ... (monodimensionale)
  • mappe multidimensionali : funzioni, mappe di mappe ...
  • tipi di grafici : alberi, grafici diretti ...

Puoi emulare qualsiasi struttura con qualsiasi altra struttura - dipende solo da quanto semplice e chiaro il linguaggio di programmazione lo consenta. Per esempio:

  • la coda e lo stack sono facili da emulare con matrici o liste, di questi forniscono operazioni come push, pop, shift ecc.
  • le sequenze ordinate possono essere emulate con mappe con tasti numerici
  • i set possono essere emulati da mappe che mappano i valori su un valore booleano
  • la maggior parte dei tipi di grafici può essere emulata da sequenze o mappe di nidificazione
  • le funzioni possono essere usate per emulare mappe se puoi facilmente modificarne la definizione

La maggior parte delle lingue fornisce almeno un tipo per le sequenze ordinate, uno per le mappe monodimensionali e uno per le mappe multidimensionali, limitato alle funzioni. Personalmente, mi mancano spesso set e ordinato strutture multidimensionali in linguaggi come Perl, PHP, JavaScript, Lua ... perché emularli non è abbastanza conveniente.


1

Penso che sia una cattiva idea avere troppi tipi di dati privilegiati che ottengono una sintassi speciale. Ciò complica inutilmente la sintassi del linguaggio, rendendo il codice più difficile da leggere, rendendo più difficile l'apprendimento per i principianti e rendendo più difficile lo sviluppo di strumenti per il linguaggio.

Va bene fare un'eccezione per un numero limitato di tipi di strutture di dati molto comuni. Probabilmente permetterei al massimo:

  • Matrici a lunghezza fissa
  • Imposta
  • HashMaps
  • Sequenze / liste
  • Record / strutture / classi

Qualcosa di più sofisticato di quello dovrebbe probabilmente essere lasciato alle librerie da gestire, usando la normale sintassi del linguaggio per tipi di dati personalizzati.

In particolare, cose come alberi rosso / nero, code prioritarie ecc. Hanno un sacco di possibili opzioni di implementazione, quindi non è saggio implementare una particolare implementazione nel linguaggio principale. È meglio consentire alle persone di scegliere l'implementazione più appropriata per la propria situazione. Esempi di scelte di implementazione sulle quali potrei non volere che un progettista di lingue limiti la mia scelta su:

  • Mutevole o immutabile?
  • Permette null o no?
  • Sincronizzato o no?
  • Supportato da memoria persistente o no?
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.