As estruturas de dados devem ser integradas à linguagem (como em Python) ou fornecidas na biblioteca padrão (como em Java)?

21

No Python, e provavelmente em muitas outras linguagens de programação, estruturas comuns de dados podem ser encontradas como uma parte integrada da linguagem principal com sua própria sintaxe dedicada. Se colocarmos de lado a sintaxe da lista integrada do LISP, não consigo pensar em outras linguagens que conheço que forneçam algum tipo de estrutura de dados acima da matriz como uma parte integrada de sua sintaxe, embora todas elas (mas C, eu acho) parecem fornecê-los na biblioteca padrão.

Do ponto de vista do design da linguagem, quais são suas opiniões sobre ter uma sintaxe específica para estruturas de dados na linguagem principal? É uma boa ideia e o objetivo do idioma (etc.) muda o quão bom isso pode ser uma escolha?

Edit: Me desculpe por (aparentemente) causar alguma confusão sobre quais estruturas de dados eu quero dizer. Eu falo sobre os básicos e comumente usados, mas ainda não os mais básicos. Isso exclui árvores (muito complexas, incomuns), pilhas (raramente usadas), matrizes (muito simples), mas inclui, por exemplo, conjuntos, listas e hashmaps.

Anto
fonte
1
Estamos excluindo o objeto e o hashmap?
Orbling 04/04
3
@Anto: Bem muitas línguas têm HashMaps na forma de matrizes associativas, Perl, PHP, JS (tecnicamente um objeto aqui), etc.
Orbling
1
Talvez você possa ser mais específico sobre quais estruturas de dados está pensando, além de matrizes, listas, hashmaps / matrizes associativas?
FrustratedWithFormsDesigner
1
Inclua hashmaps, listas e qualquer coisa mais avançada como as "estruturas de dados complexas" e jogue arrays como muito simples.
Anto 04/04
1
Eu acho que um título mais sensato seria algo como: "Quais estruturas de dados devem ser incluídas na linguagem e o que na biblioteca?" Porém, uma resposta significativa depende muito do idioma: quanto mais limpa a biblioteca for integrada ao idioma, mais razoável será mover as estruturas para a biblioteca.
perfil completo de Jerry Coffin

Respostas:

13

Depende para que serve o idioma.

Alguns exemplos (um pouco roubados de outras respostas):

  • O Perl possui uma sintaxe especial para tabelas, matrizes e seqüências de caracteres. Perl é frequentemente usado para scripts, estes são úteis para scripts.
  • O Matlab possui sintaxe especial para listas, matrizes, estruturas. O Matlab é para fazer matemática matricial e vetorial para engenharia.
  • Sequência e matrizes de suporte Java / .NET. Essas são linguagens de uso geral em que matrizes e seqüências de caracteres são frequentemente usadas (cada vez menos com o uso de novas classes de coleção)
  • Matrizes de suporte C / C ++. Esses são idiomas que não escondem o hardware de você. As strings são parcialmente suportadas (sem concatenação, use strcpy, etc.)

Eu acho que depende de qual é o propósito / espírito / público da sua língua; quão abstrato e a que distância do hardware você deseja que ele seja. Geralmente os idiomas que suportam listas como primitivas permitem criar listas infinitamente longas. Embora um nível baixo como C / C ++ nunca os tenha, porque esse não é o objetivo, o espírito dessas linguagens.

Para mim, a coleta de lixo segue a mesma lógica: o público do seu idioma se importa em saber exatamente quando e se a memória está sendo alocada ou liberada? Se sim, malloc / free; se não, coleta de lixo.

earlNameless
fonte
6
Este é um lugar ruim para usar o termo "C / C ++", porque a presença de tipos de modelo de alto nível no C ++ é uma grande diferença entre os dois idiomas.
dan04
A coleta de lixo pode ser feita de maneira determinística, você só precisa de tipos lineares (ou a substituição do pobre deles: RAII).
P4
@ EduardoLeón, embora você possa chamar a coleta de lixo em um ponto determinístico, não acho que por quanto tempo ele será executado é determinístico (pelo mesmo motivo malloce newnão determinístico em C / C ++).
earlNameless
@earlNameless: É determinístico em relação ao uso do recurso: tipos lineares (ou tipos de exclusividade, que são semelhantes) tornam um erro de tipo (e, portanto, erro de compilação) para não liberar recursos (modulo da possibilidade, não capturado pelo tipo qualquer encerramento anormal do programa) ou para utilizá-los após serem descartados.
pyon
5

O Perl tem hashmaps e o PL / SQL suporta registros, e eu tenho memórias muito nebulosas do matlab com sintaxe para suportar vetores e matrizes de todas as dimensões diferentes (embora eu possa estar errado sobre isso e possa ser argumentado que esses são tipos de dados e não dados) estruturas ) ... eu diria que é bom ter algum suporte nativo para estruturas muito comuns. Geralmente, parece que matrizes e hashmaps / matrizes associativas são as estruturas suportadas nativamente mais comuns e provavelmente são as mais usadas também.

Não esqueça que se você adicionar suporte à sintaxe nativa para outras estruturas, como árvores binárias, essas estruturas também serão implementadas pelas ferramentas de suporte da linguagem (compilador / tempo de execução / etc). Para quantos estruturas você deseja criar suporte?

Você terá que inventar uma nova notação para as estruturas com suporte nativo menos comum ... Keep It Simple !.

FrustratedWithFormsDesigner
fonte
Não há necessidade de inventar uma sintaxe literal para, por exemplo, árvores - elas são mais raras, nem estão no stdlib de muitas línguas! Pelo mesmo argumento, alguém poderia se opor à inclusão de operadores porque "você teria que inventar uma nova notação para as operações menos usadas".
@ delnan: Do jeito que eu entendi, da perspectiva de projetar uma nova linguagem e me perguntar se as estruturas de dados além de matrizes devem ou não ser suportadas nativamente por (possivelmente) nova sintaxe, ou se devem ser suportadas pela inclusão de uma biblioteca.
FrustratedWithFormsDesigner
Bem, a primeira frase fala explicitamente sobre "estruturas de dados comuns", então presumo que o OP não seja insano o suficiente para tentar adicionar sintaxe especial para todas as estruturas de dados obscuras já inventadas.
@ delnan: ... e então o OP continua excluindo listas e matrizes LISP (em geral) "... coloque a sintaxe da lista integrada do LISP de lado, não consigo pensar em nenhum outro idioma que eu conheça que ofereça algum tipo de estrutura de dados acima da variedade como parte integrante de sua sintaxe" ... então eu pensei que eles estavam pensando estruturas de dados mais exótico do que matrizes / listas ...
FrustratedWithFormsDesigner
Sim (eu interpretei "acima das matrizes" como "outras estruturas de dados comuns"), mas nada na pergunta sugere "vamos fazer literais para cada estrutura de dados que temos". É bom afirmar que isso deve se limitar ao que é razoável, mas não acho que possamos dizer "má ideia" apenas por causa dessa suposição .
5

Meu exemplo favorito aqui é Lua . Lua possui apenas um tipo de dados embutido, a " tabela ", mas sua flexibilidade e velocidade significam que você realmente os usa no lugar de matrizes regulares, listas vinculadas, filas, mapas e são até a base para os recursos orientados a objetos de Lua (ou seja, aulas).

Lua é uma linguagem incrivelmente simples, mas a flexibilidade da estrutura de dados da tabela também a torna bastante poderosa.

Dean Harding
fonte
2
Objetos JavaScript são realmente da mesma maneira - matrizes são realmente objetos com propriedades numéricas e comprimento, por exemplo.
Tikhon Jelvis
1
As tabelas Lua são diferentes dos objetos JavaScript: no JavaScript {}não [], no Lua você tem {}para ambos. As tabelas Lua se comparam melhor às listas no Lisp.
Jakob
Eu acho que em JavaScript, "tudo é um objeto" - incluindo matrizes - mas nem tudo é uma matriz. Em Lua, tudo é uma mesa.
Dean Harding
3

Você não precisa ter sintaxe dedicada para todos os tipos de dados de alto nível. Por exemplo, é aceitável ter set([1, 2, 3])(como o Python 2.x) em vez de {1, 2, 3}.

O importante é ter alguma forma conveniente para a construção de uma estrutura de dados de alto nível. O que você deseja evitar é um código como:

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

o que me irrita muito quando eu uso std::vector, std::sete std::mapem C ++. Felizmente, o novo padrão terá std::initializer_list.

dan04
fonte
3

Na minha opinião, é uma adição incrivelmente simples que pode ser útil surpreendentemente com frequência, pelo menos se for feita com cautela - ou seja, no máximo para tuplas, listas, mapas e conjuntos, pois possuem literais bem reconhecidos.

  • É barato adicionar a um idioma. Não custa muito desse precioso orçamento de complexidade:
    • a gramática é basicamente someBracket {expr ','} someBracketou someBracket {expr ':' expr ','} someBracket, com alguns extras simples, se você quiser coisas como vírgulas finais à direita. Os literais flutuantes podem facilmente ser mais longos na gramática.
    • Em muitas linguagens, nenhum dos literais populares entra em conflito com a sintaxe existente (uma exceção que consigo pensar é uma linguagem com blocos semelhantes a chaves como expressões, um operador de vírgula e sem ponto e vírgula, como em {1, 2})
    • A semântica pode ser definida em menos de cinco sentenças, sendo a versão informal "Instanciar uma nova coleção $, em seguida, chame .add/ .append/ .setItemuma vez por expressões especificadas com essa (essas) expressão (s) como argumento".
  • Devido ao terceiro ponto anterior, também é muito fácil de implementar.
  • Ele é incrivelmente útil quando você precisa de um e não afeta a sintaxe de outros elementos, ou seja, você não "paga" por isso quando não o usa.
mosquito
fonte
3

Clojure é um cisco, mas suporta

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

Quanto mais estruturas de dados você tiver no próprio idioma, mais difícil será o aprendizado do idioma. Pode ser uma preferência pessoal, mas eu tendem a preferir uma linguagem mais simples e, em seguida, quaisquer extras podem ser fornecidos pelas bibliotecas.

Às vezes, os idiomas projetados para campos específicos podem se beneficiar da incorporação de determinadas estruturas de dados no idioma, como o Matlab. Mas muitos podem sobrecarregar você.

ergodicsum
fonte
2

Para que um idioma seja realmente útil, ele precisa executar um certo grau de tarefas imediatamente. Porque a programação prática diária requer ferramentas que resolvam seus problemas em algum nível genérico. O minimalismo parece compacto e legal, mas quando você deseja começar a usar para solucionar problemas grandes, mas repetidos, precisa de um nível de abstração sobre o qual possa desenvolver.

Então, acho que as linguagens de programação devem fornecer suporte para as estruturas de dados mais usadas na sintaxe para as tarefas para as quais a linguagem foi projetada.

kamaal
fonte
2

Em geral, acho conveniente ter literais para listas, conjuntos e assim por diante. Mas às vezes me incomoda que eu não saiba nada sobre a implementação real - digamos - da lista Python ou da matriz Javascript. A única coisa que posso ter certeza é que eles expõem uma determinada interface.

Tomo como referência de uma expressividade da linguagem o quão bem ele pode escrever suas próprias estruturas de dados como bibliotecas e quão conveniente é usá-las.

Por exemplo, o Scala fornece várias coleções com diferentes garantias de implementação e desempenho. Todos eles são implementados no próprio Scala, e a sintaxe para usá-los é apenas um pouco mais complexa do que se eles estivessem embutidos e tivessem suporte ao tempo de execução.

A única estrutura básica que realmente precisa de suporte do próprio tempo de execução, pelo menos em uma linguagem gerenciada, é a matriz: se você não gerenciar a memória, será difícil obter vários bytes adjacentes. Qualquer outra estrutura pode ser construída com matrizes e ponteiros (ou referências).

Andrea
fonte
1

APL (e variantes modernas relacionadas, A +, J e K) têm escalar, vetor e matriz como estruturas de dados de primeira classe.

Sim, eles podem ser preteridos como meras variantes na matriz. Mas eles também estão livres de declarações complexas e não vêm de uma biblioteca separada; eles se parecem com estruturas de dados complexas que são uma parte de primeira classe da linguagem.

S.Lott
fonte
O APL também possui matrizes aninhadas e não precisam ter tipos de dados homogêneos, o que cria estruturas de dados muito poderosas.
RFlack 24/05
1

Do ponto de vista do design da linguagem, quais são suas opiniões sobre ter uma sintaxe específica para estruturas de dados na linguagem principal? É uma boa ideia e o objetivo do idioma (etc.) muda o quão bom isso pode ser uma escolha?

Literais de lista e mapa e uma sintaxe de fechamento conveniente são recursos essenciais de idiomas de alto nível.

A diferença entre este código Java:

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

e este código Groovy:

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

é enorme. É a diferença entre um programa de 40.000 linhas e um programa de 10.000 linhas. A sintaxe é importante.

Kevin Cline
fonte
Em C #, pode-se fazer: var t = new Thing(foo: 3, bar: 6.3, baz: true);- apenas mais 4 caracteres.
Job
é realmente o mesmo número; o código Groovy deve ler 'def t = ...'
kevin Cline
1

Claro que depende da aplicação da linguagem de programação, mas para linguagens de nível superior, deve ser o mais conveniente possível trabalhar com qualquer estrutura de dados comum. Dê uma olhada na lista de tipos de dados abstratos na Wikipedia para exemplos. Encontrei os seguintes princípios básicos mais comuns (mas também gostaria de ouvir outras opiniões):

  • sequências ordenadas (unidimensionais): matriz, fila, pilha, listas ...
  • estruturas multidimensionais ordenadas : tabela, vetor, matriz ..
  • mapas : hashmap, dicionário, conjunto, multimapa ... (unidimensional)
  • mapas multidimensionais : funções, mapas de mapas ...
  • tipos de gráfico : árvores, gráficos direcionados ...

Você pode emular qualquer estrutura com qualquer outra estrutura - isso depende apenas de quão fácil e clara a linguagem de programação permite. Por exemplo:

  • a fila e a pilha são fáceis de emular com matrizes ou listas; estas fornecem operações como push, pop, shift etc.
  • sequências ordenadas podem ser emuladas com mapas que possuem teclas numéricas
  • conjuntos podem ser emulados por mapas que mapeiam valores para um valor booleano
  • a maioria dos tipos de gráficos pode ser emulada, aninhando seqüências ou mapas
  • funções podem ser usadas para emular mapas se você pode modificar facilmente sua definição

A maioria dos idiomas fornece pelo menos um tipo para seqüências ordenadas, um para mapas unidimensionais e outro para mapas multidimensionais, limitado a funções. Pessoalmente, muitas vezes sinto falta de conjuntos e ordeno estruturas multidimensionais em linguagens como Perl, PHP, JavaScript, Lua ... porque emulá-las não é conveniente o suficiente.

Jakob
fonte
1

Eu acho que é uma má idéia ter muitos tipos de dados privilegiados que obtêm sintaxe especial. Isso complica desnecessariamente a sintaxe da linguagem, dificultando a leitura do código, dificultando a aprendizagem dos iniciantes e dificultando o desenvolvimento de ferramentas para a linguagem.

Não há problema em abrir uma exceção para um pequeno número de tipos de estrutura de dados muito comuns. Eu provavelmente permitiria no máximo:

  • Matrizes de comprimento fixo
  • Conjuntos
  • Hashmaps
  • Sequências / listas
  • Registros / estruturas / classes

Qualquer coisa mais sofisticada que isso provavelmente deve ser deixada para as bibliotecas manipularem, usando a sintaxe normal da linguagem para tipos de dados personalizados.

Em particular, coisas como árvores Vermelho / Preto, Filas Prioritárias etc. têm muitas opções de implementação possíveis, portanto, não é aconselhável incluir uma implementação específica no idioma principal. É melhor permitir que as pessoas escolham a implementação mais apropriada para sua situação. Exemplos de opções de implementação nas quais eu talvez não queira que um designer de idioma restrinja minha escolha:

  • Mutável ou imutável?
  • Permite nulos ou não?
  • Sincronizado ou não?
  • Apoiado por armazenamento persistente ou não?
Mikera
fonte