¿Deberían integrarse las estructuras de datos en el lenguaje (como en Python) o proporcionarse en la biblioteca estándar (como en Java)?

21

En Python, y muy probablemente en muchos otros lenguajes de programación, se pueden encontrar estructuras de datos comunes como una parte integrada del lenguaje central con su propia sintaxis dedicada. Si dejamos de lado la sintaxis de lista integrada de LISP, no puedo pensar en ningún otro lenguaje que conozca que proporcione algún tipo de estructura de datos sobre la matriz como parte integrada de su sintaxis, aunque todos ellos (pero C, supongo) parecen proporcionarlos en la biblioteca estándar.

Desde la perspectiva del diseño del lenguaje, ¿cuáles son sus opiniones sobre tener una sintaxis específica para las estructuras de datos en el lenguaje central? ¿Es una buena idea, y el propósito del lenguaje (etc.) cambia lo bueno que esto podría ser una elección?

Editar: siento (aparentemente) causar cierta confusión sobre a qué estructuras de datos me refiero. Hablo de los básicos y de uso común, pero aún no son los más básicos. Esto excluye árboles (demasiado complejos, poco comunes), pilas (muy raramente utilizadas), matrices (demasiado simples) pero incluye, por ejemplo, conjuntos, listas y hashmaps.

Anto
fuente
1
¿Estamos excluyendo el objeto y el hashmap?
Orbling
3
@Anto: Bueno, muchos lenguajes tienen hashmaps en forma de matrices asociativas, Perl, PHP, JS (técnicamente un objeto aquí), etc.
Orbling
1
¿Quizás podría ser más específico sobre las estructuras de datos en las que está pensando, además de las matrices, listas, hashmaps / matrices asociativas?
FrustratedWithFormsDesigner
1
Incluya hashmaps, listas y cualquier cosa más avanzada como "estructuras de datos complejas" y deseche las matrices como demasiado simples.
Anto
1
Creo que un título más sensato sería algo así como: "¿Qué estructuras de datos deberían incluirse en el lenguaje y qué en la biblioteca?" Sin embargo, una respuesta significativa depende en gran medida del idioma: cuanto más limpiamente se integra la biblioteca en el idioma, más razonable es mover las estructuras a la biblioteca.
Jerry Coffin

Respuestas:

13

Depende de para qué es el idioma.

Algunos ejemplos (algo robado de otras respuestas):

  • Perl tiene una sintaxis especial para tablas hash, matrices, cadenas. Perl se usa a menudo para las secuencias de comandos, estas son útiles para las secuencias de comandos.
  • Matlab tiene una sintaxis especial para listas, matrices, estructuras. Matlab es para hacer matemáticas de matriz y vectoriales para ingeniería.
  • Java / .NET admite cadenas y matrices. Estos son lenguajes de propósito general en los que a menudo se usan matrices y cadenas (cada vez menos con el uso de nuevas clases de colección)
  • C / C ++ soporta matrices. Estos son idiomas que no te ocultan el hardware. Las cadenas son parcialmente compatibles (sin concatenación, uso strcpy, etc.)

Creo que depende de cuál sea el propósito / espíritu / audiencia de su idioma; qué tan abstracto y qué tan lejos del hardware quieres que esté. En general, los idiomas que admiten listas como primitivas le permiten crear listas infinitamente largas. Si bien los niveles bajos como C / C ++ nunca los tendrían, porque ese no es el objetivo, el espíritu de esos lenguajes.

Para mí, la recolección de basura sigue la misma lógica: ¿le importa a la audiencia de su idioma saber exactamente cuándo y si se está asignando o liberando memoria? En caso afirmativo, malloc / libre; si no, entonces recolección de basura.

earlNameless
fuente
66
Este es un mal lugar para usar el término "C / C ++", porque la presencia de tipos de plantillas de alto nivel en C ++ es una gran diferencia entre los dos lenguajes.
dan04
La recolección de basura se puede hacer de manera determinista, solo necesita tipos lineales (o el reemplazo de su pobre: ​​RAII).
pyon
@ EduardoLeón, aunque se puede llamar a la recolección de basura en un punto determinista, no creo que el tiempo que tendrá una duración de es determinista (por la misma razón que mallocy newson no-determinista en C / C ++).
earlNameless
@earlNameless: es determinista en relación con el uso del recurso: los tipos lineales (o tipos de unicidad, que son similares) lo convierten en un error de tipo (y, por lo tanto, un error de compilación) para no liberar recursos (módulo de la posibilidad, no capturado por el tipo sistema, de cualquier terminación anormal del programa), o para usarlos después de que hayan sido eliminados.
pyon
5

Perl tiene hashmaps y PL / SQL admite registros, y tengo recuerdos muy confusos de que matlab tiene sintaxis para admitir vectores y matrices de todas las diferentes dimensiones (aunque podría estar equivocado sobre este y podría argumentarse que estos son tipos de datos, no datos estructuras ) ... Diría que es bueno tener algo de soporte nativo para estructuras muy comunes. Por lo general, parece que las matrices y los hashmaps / matrices asociativas son las estructuras admitidas de forma nativa más comunes, y probablemente también sean las más utilizadas.

No olvide que si agrega soporte de sintaxis nativa para otras estructuras, como árboles binarios, esas estructuras también se implementarán mediante las herramientas de soporte del lenguaje (compilador / tiempo de ejecución / etc.). ¿Para cuántas estructuras desea construir soporte?

Tendrá que inventar una nueva notación para las estructuras menos comúnmente soportadas de forma nativa ... Keep It Simple !.

FrustratedWithFormsDesigner
fuente
No hay necesidad de inventar una sintaxis literal para, por ejemplo, árboles: ¡son más raros, ni siquiera están en el estándar de muchos idiomas! Por el mismo argumento, uno podría oponerse a la inclusión de operadores porque "tendría que inventar una nueva notación para las operaciones menos utilizadas".
@delnan: La forma en que lo entendí fue desde la perspectiva de diseñar un nuevo lenguaje y preguntarme si las estructuras de datos además de las matrices deberían ser compatibles de forma nativa con (posiblemente) una nueva sintaxis, o si deberían ser compatibles al incluir una biblioteca.
FrustratedWithFormsDesigner
Bueno, la primera oración explícitamente habla de "estructuras de datos comunes", por lo que supongo que OP no es lo suficientemente loco como para tratar de agregar una sintaxis especial para cada estructura de datos oscura que se haya inventado.
@delnan: ... y luego el OP continúa excluyendo listas y matrices de LISP (en general) "... deje a un lado la sintaxis de lista integrada de LISP, no puedo pensar en ningún otro idioma que conozca que ofrezca algún tipo de estructura de datos por encima de la matriz como parte integrada de su sintaxis "... así que pensé que estaban considerando estructuras de datos más exóticas que las matrices / listas ...
FrustratedWithFormsDesigner
Sí (interpreté "encima de las matrices" como "otras estructuras de datos comunes"), pero nada en la pregunta sugiere "hagamos literales para cada estructura de datos que tengamos". Está bien decir que esto debería limitarse a lo que es razonable, pero no creo que podamos decir "mala idea" solo por esta suposición .
5

Mi ejemplo favorito aquí es Lua . Lua solo tiene un tipo de datos incorporado, la " tabla ", pero su flexibilidad y velocidad significa que realmente los usa en lugar de arreglos regulares, listas vinculadas, colas, mapas e incluso son la base de las características orientadas a objetos de Lua (es decir, clases).

Lua es un lenguaje increíblemente simple, pero la flexibilidad de la estructura de datos de la tabla también lo hace bastante poderoso.

Dean Harding
fuente
2
Los objetos de JavaScript son realmente de la misma manera: las matrices son realmente objetos con propiedades numéricas y una longitud, por ejemplo.
Tikhon Jelvis el
1
Las tablas de Lua son diferentes a los objetos de JavaScript: en JavaScript {}no lo es [], en Lua tienes {}para ambos. Las tablas Lua se comparan mejor con las listas de Lisp.
Jakob
Supongo que en JavaScript, "todo es un objeto", incluidas las matrices, pero no todo es una matriz. En Lua, todo es una mesa.
Dean Harding
3

No tiene que tener una sintaxis dedicada para cada tipo de datos de alto nivel. Por ejemplo, es tolerable tener set([1, 2, 3])(como lo hizo Python 2.x) en lugar de {1, 2, 3}.

Lo importante es tener algo de manera conveniente para la construcción de una estructura de datos de alto nivel. Lo que quieres evitar es código como:

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

lo que me molesta mucho cuando uso std::vector, std::sety std::mapen C ++. Afortunadamente, el nuevo estándar tendrá std::initializer_list.

dan04
fuente
3

En mi opinión, es una adición increíblemente simple que puede ser útil sorprendentemente a menudo, al menos si se hace con precaución, es decir, como máximo para tuplas, listas, mapas y conjuntos, ya que tienen literales bien reconocidos.

  • Es barato agregar a un idioma. No le cuesta mucho de ese precioso presupuesto de complejidad:
    • la gramática es básicamente someBracket {expr ','} someBracketo someBracket {expr ':' expr ','} someBracket, con algunos extras simples muertos si quieres cosas como comas finales opcionales. Los literales flotantes pueden fácilmente ser más largos en la gramática.
    • En muchos idiomas, ninguno de los literales populares choca con la sintaxis existente (una excepción que se me ocurre es un lenguaje con bloques parecidos a llaves como expresiones, un operador de coma y sin punto y coma, como en {1, 2})
    • La semántica se puede definir en menos de cinco oraciones, la versión informal es "Crear una nueva colección $, luego llamar .add/ .append/ .setItemuna vez por expresiones dadas con esa (esas) expresión (s) como argumentos".
  • Debido al tercer punto anterior, también es muy fácil de implementar.
  • Es increíblemente útil cuando lo necesita, y no (necesita) afectar la sintaxis de otros elementos, es decir, no "paga" cuando no lo usa.
mosquito
fuente
3

Clojure es un lisp pero soporta

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

Cuantas más estructuras de datos tenga en el propio lenguaje, más difícil será aprender el idioma. Puede ser una preferencia personal, pero tiendo a preferir un lenguaje más simple y luego las bibliotecas pueden proporcionar cualquier extra.

Los lenguajes diseñados para campos específicos a veces pueden beneficiarse de tener ciertas estructuras de datos integradas en el lenguaje, como Matlab. Pero demasiados pueden abrumarte.

ergodicsum
fuente
2

Para que un lenguaje sea realmente útil, tiene que realizar un cierto grado de tareas fuera de la caja. Porque la programación práctica del día a día requiere herramientas que resuelvan sus problemas en algún nivel genérico. El minimalismo se ve compacto y genial, pero cuando quieres comenzar a usarlo para resolver problemas grandes pero repetidos, necesitas un nivel de abstracción sobre el cual puedas construir.

Por lo tanto, creo que los lenguajes de programación deberían enviar soporte para las estructuras de datos más utilizadas en la sintaxis para las tareas para las que está diseñado el lenguaje.

kamaal
fuente
2

En general, me parece conveniente tener literales para listas, conjuntos, etc. Pero a veces me molesta que no sepa nada sobre la implementación real de, digamos, la lista de Python o la matriz de Javascript. De lo único que puedo estar seguro es de que exponen una interfaz determinada.

Tomo como punto de referencia de la expresividad de un lenguaje qué tan bien puede escribir sus propias estructuras de datos como bibliotecas, y qué tan conveniente es usarlas.

Por ejemplo, Scala ofrece varias colecciones con diferentes garantías de implementación y rendimiento. Todos ellos están implementados en Scala, y la sintaxis para usarlos es solo un poco más compleja que si estuvieran incorporados y tuvieran tiempo de ejecución.

La única estructura básica que realmente necesita soporte del propio tiempo de ejecución, al menos en un lenguaje administrado, es la matriz: si no administra la memoria, tendrá dificultades para obtener un montón de bytes adyacentes. Cualquier otra estructura puede construirse a partir de matrices y punteros (o referencias).

Andrea
fuente
1

APL (y las variantes modernas relacionadas, A +, J y K) tienen estructuras escalares, vectoriales y matriciales como estructuras de datos de primera clase.

Sí, pueden ser desaprobados como simples variantes en la matriz. Pero también están libres de declaraciones complejas y no provienen de una biblioteca separada, se sienten como estructuras de datos complejas que son una parte de primera clase del lenguaje.

S.Lott
fuente
APL también tiene matrices anidadas, y las matrices no tienen que tener un tipo de datos homogéneo, lo que crea estructuras de datos muy potentes.
RFlack
1

Desde la perspectiva del diseño del lenguaje, ¿cuáles son sus opiniones sobre tener una sintaxis específica para las estructuras de datos en el lenguaje central? ¿Es una buena idea, y el propósito del lenguaje (etc.) cambia lo bueno que esto podría ser una elección?

Los literales de listas y mapas y una conveniente sintaxis de cierre son características esenciales de los lenguajes de alto nivel.

La diferencia entre este código Java:

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

y este código Groovy:

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

es enorme Es la diferencia entre un programa de 40,000 líneas y un programa de 10,000 líneas. La sintaxis importa.

Kevin Cline
fuente
En C # one puede hacer: var t = new Thing(foo: 3, bar: 6.3, baz: true);- solo 4 caracteres más.
Trabajo
en realidad es el mismo número; el código Groovy debería leer 'def t = ...'
kevin cline
1

Claro que depende de la aplicación del lenguaje de programación, pero para los lenguajes de nivel superior debería ser lo más conveniente posible trabajar con cualquier estructura de datos común. Eche un vistazo a la lista de tipos de datos abstractos en Wikipedia para ver ejemplos. Encontré los siguientes principios básicos más comunes (pero también me gustaría escuchar otras opiniones):

  • secuencias ordenadas (unidimensionales): matriz, cola, pila, listas ...
  • estructuras multidimensionales ordenadas : tabla, vector, matriz ...
  • mapas : hashmap, diccionario, conjunto, multimapa ... (unidimensional)
  • mapas multidimensionales : funciones, mapas de mapas ...
  • tipos de gráficos : árboles, gráficos dirigidos ...

Puede emular cualquier estructura con cualquier otra estructura; solo depende de cuán fácil y claro lo permita el lenguaje de programación. Por ejemplo:

  • cola y pila son fáciles de emular con matrices o listas, de estas últimas operaciones como push, pop, shift, etc.
  • las secuencias ordenadas se pueden emular con mapas que tienen teclas numéricas
  • los conjuntos pueden ser emulados por mapas que asignan valores a un valor booleano
  • la mayoría de los tipos de gráficos se pueden emular anidando secuencias o mapas
  • las funciones se pueden usar para emular mapas si puede modificar fácilmente su definición

La mayoría de los idiomas proporcionan al menos un tipo para secuencias ordenadas, uno para mapas unidimensionales y otro para mapas multidimensionales, limitado a funciones. Personalmente, a menudo extraño conjuntos y estructuras multidimensionales ordenadas en lenguajes como Perl, PHP, JavaScript, Lua ... porque emularlos no es lo suficientemente conveniente.

Jakob
fuente
1

Creo que es una mala idea tener demasiados tipos de datos privilegiados que obtienen una sintaxis especial. Esto complica la sintaxis del lenguaje innecesariamente, dificultando la lectura del código, dificultando el aprendizaje de los principiantes y el desarrollo de herramientas para el idioma.

Está bien hacer una excepción para un pequeño número de tipos de estructura de datos muy comunes. Probablemente permitiría como máximo:

  • Arreglos de longitud fija
  • Conjuntos
  • Hashmaps
  • Secuencias / listas
  • Registros / estructuras / clases

Algo más sofisticado que eso probablemente debería dejarse en manos de las bibliotecas, utilizando la sintaxis normal del lenguaje para los tipos de datos personalizados.

En particular, cosas como árboles rojos / negros, colas de prioridad, etc. tienen muchas opciones de implementación posibles, por lo que no es aconsejable hornear una implementación particular en el lenguaje principal. Es mejor dejar que las personas elijan la implementación más adecuada para su situación. Ejemplos de opciones de implementación en las que quizás no quiera que un diseñador de idiomas restrinja mi elección:

  • Mutable o inmutable?
  • Permite nulos o no?
  • ¿Sincronizado o no?
  • Respaldado por el almacenamiento persistente o no?
mikera
fuente