Quais são os exemplos de inconsistência e incompletude no Unix / C?

20

No famoso ensaio de Richard Gabriel, The Rise of Worse is Better , ele contrasta versões caricaturadas das filosofias de design do MIT / Stanford (Lisp) e Nova Jersey (C / Unix) ao longo dos eixos da simplicidade, correção, consistência e perfeição. Ele dá o exemplo do "problema de perdedor de PC" ( discutido em outro lugar por Josh Haberman ) para argumentar que o Unix prioriza a simplicidade de implementação em detrimento da simplicidade de interface.

Outro exemplo que inventei são as diferentes abordagens dos números. O Lisp pode representar números arbitrariamente grandes (até o tamanho da memória), enquanto C limita os números a um número fixo de bits (geralmente 32 a 64). Eu acho que isso ilustra o eixo de correção.

Quais são alguns exemplos de consistência e integridade? Aqui estão todas as descrições de Gabriel (que ele admite serem caricaturas):

A abordagem do MIT / Stanford

  • Simplicidade - o design deve ser simples, tanto na implementação quanto na interface. É mais importante que a interface seja simples que a implementação.
  • Correção - o projeto deve estar correto em todos os aspectos observáveis. Incorretividade simplesmente não é permitida.
  • Consistência - o design não deve ser inconsistente. É permitido que um design seja um pouco menos simples e menos completo para evitar inconsistências. A consistência é tão importante quanto a correção.
  • Completude - o design deve abranger o maior número possível de situações importantes. Todos os casos razoavelmente esperados devem ser cobertos. A simplicidade não pode reduzir excessivamente a integridade.

A abordagem de Nova Jersey

  • Simplicidade - o design deve ser simples, tanto na implementação quanto na interface. É mais importante que a implementação seja simples que a interface. Simplicidade é a consideração mais importante em um design.
  • Correção - o projeto deve estar correto em todos os aspectos observáveis. É um pouco melhor ser simples do que correto.
  • Consistência - o design não deve ser excessivamente inconsistente. A consistência pode ser sacrificada pela simplicidade em alguns casos, mas é melhor descartar as partes do design que lidam com circunstâncias menos comuns do que introduzir complexidade ou inconsistência na implementação.
  • Completude - o design deve abranger o maior número possível de situações importantes. Todos os casos razoavelmente esperados devem ser cobertos. A integridade pode ser sacrificada em favor de qualquer outra qualidade. De fato, a integridade deve ser sacrificada sempre que a simplicidade da implementação é comprometida. A consistência pode ser sacrificada para alcançar a integridade se a simplicidade for mantida; especialmente inútil é a consistência da interface.

Observe que não estou perguntando se Gabriel está certo (que é uma pergunta não apropriada para o StackExchange), mas para exemplos do que ele pode estar se referindo.

Ellen Spertus
fonte
6
Caso você esteja curioso, isso não é um problema de lição de casa. Eu sou a professora :-) Pensando bem, talvez isso faça da minha lição de casa.
Ellen Spertus
4
Eu luto para ver por que essa pergunta não está no Unix e Linux (ou talvez Engenharia de Software ?). Você pode elaborar de que maneira você precisa de uma perspectiva de CS sobre o assunto? Além disso, esclareça se deseja exemplos positivos ou negativos.
Raphael
Essa pergunta não é mais adequada em programmers.stackexchange.com ?
Basile Starynkevitch
Publiquei isso no CS porque considero o design de linguagem uma das áreas profundas fundamentais da ciência da computação, abrangendo computabilidade, complexidade, arquitetura, usabilidade etc. Eu poderia publicá-lo no Unix / Linux, embora estivesse procurando um Visão. Quanto aos programadores, as pessoas quase sempre são hostis a mim quando eu posto lá, mesmo quando penso que estou no assunto, então fico longe de lá.
Ellen Spertus

Respostas:

15

O título da pergunta sugere que algumas inconsistências básicas da interface do usuário podem lhe interessar:

Os comandos Unix não seguem nenhuma sintaxe específica para especificar opções e sinalizadores. Por exemplo, a maioria dos comandos usa letras únicas precedidas por '-' como sinalizador cat -n some_file:, mas exceções como tar tf some_file.tare dd in=some_file out=some_other_file count=2existem nos comandos comumente usados.

O Unix e seus descendentes e parentes têm várias sintaxes de expressão regular ligeiramente diferentes. Os shells usam "*" onde outros programas (grep, egrep, vi) usam '. *'. O egrep possui '+' e '|' como operadores, o grep não.

A interface básica de chamada do sistema "tudo é um arquivo" pode ser vista como incompleta: leitura / gravação / busca / fechamento não se encaixa em todos os dispositivos de E / S. As exceções muito necessárias são agrupadas nas chamadas "ioctl", mas dispositivos como placas de som nem se encaixam muito bem.

Bruce Ediger
fonte
Boa resposta. Quando vi o título, pensei imediatamente em "ioctl" (e fcntl), mas agora não preciso digitar uma resposta.
Louis
1
padrões glob não são regexs
jk.
8

Consistência

O Lisp tem uma sintaxe muito consistente, todas as extensões de idioma podem ser incorporadas naturalmente via macros e tal. C, por outro lado, possui uma sintaxe de código, que permite a utilização de alguns "atalhos"; portanto, em alguns casos, o código C parece realmente mais simples.

Completude

No Lisp, se você não possui um recurso específico de idioma, precisa implementá-lo com macros. C também possui pré-processador, mas é bastante desconcertante.

Daniil
fonte
8

As strings de C não podem conter o caractere 0 e suas funções de biblioteca não são adequadas para lidar com dados binários.

Os nomes de arquivos nos sistemas Unix não podem conter o caractere 0 ou 47 (a barra).

Na implementação original do Unix, os nomes de arquivos eram limitados a 14 caracteres. Versões posteriores apenas relaxaram essa limitação; eles não o eliminaram.

Adicionado : a E2BIGcondição de erro do sistema, quando alguém tentava execcom uma lista de argumentos com muitos argumentos ou ocupava muita memória ou um ambiente muito grande.

O Unix é notório por esse tipo de limitação arbitrária. Até o advento do Perl, em 1987, o manuseio de grandes conjuntos de dados, ou conjuntos de dados com registros longos ou dados binários, era extremamente confiável.

Mark Dominus
fonte
Não permitir /não é arbitrário, é necessário (?) Resolver ambiguidades como /é o separador de caminho. Acabei de criar um arquivo 000, aparentemente essa restrição específica desapareceu nos dias de um GNU / Linux moderno.
Raphael
Eu não quis dizer que a proibição de /era arbitrária, apenas que o comprimento da linha e os limites de tamanho do arquivo eram arbitrários. O ponto, no entanto, é que um design diferente poderia ter permitido que os nomes de arquivos contivessem barras, mas os designers do Unix não considere importante.
Mark Dominus
Estou certo de que, na época, esses limites foram introduzidos devido a considerações de desempenho; técnicas não desenvolvidas também podem ser usadas. Do ponto de vista de hoje, eles parecem questionáveis, com certeza. Quanto a isso /, estou curioso: assumindo que um caminho deve ser codificado como string, como você faz isso sem um caractere reservado para a separação de caminhos?
Raphael
Eu não entendo qual é o seu ponto. A pergunta pede "exemplos de inconsistência e incompletude no Unix / C"; não menciona desempenho.
precisa
1
@ Rafael: Você se livra dos problemas do separador bobo definindo um pathtipo de dados abstratos e usa-o em suas interfaces em vez de expor uma implementação específica (seqüências ascii terminadas em nulo).
Wandering Logic
4

IIRC meu professor disse que a incapacidade de usar char *variáveis ​​nas switchdeclarações em C é uma questão de inconsistência, mas para mim isso foi questão de generalidade (completude). Eu acho que é melhor usar "consistência" apenas nos seus algoritmos ou design de software, não na própria linguagem de programação (pelo menos não em linguagens como C. talvez uma linguagem de buggy tenha problema de consistência), porque as linguagens de programação têm padrões sólidos que definem o domínio das regras e trabalhe aplicando informações às regras. Portanto, se algo não é permitido na linguagem, planejou não ser permitido e não é inconsistência na linguagem, IMHO.


  1. Eu usei a generalidade como perfeição. Eu acho que eles são a mesma coisa. talvez eu esteja errado.
  2. Esta não é uma resposta. talvez sugestão ou minha opinião.
viciado
fonte
3

O melhor exemplo que tenho é o usuário pobre que teve um arquivo nomeado .. -re digitado rm *.

Se essa história é verdadeira ou não, tornou-se o clássico de um odiador do Unix.

Veja The Unix-Haters Handbook , que tem uma introdução do próprio Dennis Ritchie, para muitos desses exemplos.

Acrescentarei ainda que evitar esse tipo de problema foi uma força importante no design do Power Shell da Microsoft.

S. Robert James
fonte
Eu li o ensaio de Richard Gabriel no final do The Unix-Haters Handbook. :-)
Ellen Spertus
3
  • Certamente, os inúmeros significados das mesmas (curtas) bandeiras para comandos são uma inconsistência.
  • Cada programa que usa expressões regulares possui sua própria sintaxe.
  • Os arquivos de configuração dos serviços são todos de sintaxe diferente (que pode ser perdoada em parte, o daemon do seu mailer tem pouco em comum com o servidor da web ou a inicialização do sistema, mas ainda assim)
  • Existem editores diferentes! Os usuários usam conchas diferentes !! Por que existem tantos ambientes de desktop?!?

OTOH, o fato de o shell expandir os globs, e não o programa, elimina muitas inconsistências irritantes presentes em outros sistemas. Ademais, é possível usar o mesmo comando para copiar um arquivo de um lugar para outro no arquivo de arquivo, para um disquete ou de um disco Zip para fita.

Então, sim, o Unix é inconsistente. Assim como os outros sistemas, apenas de forma diferente ;-)

vonbrand
fonte
2

O LISP que suporta números de precisão infinitos versus C que suporta apenas números inteiros da máquina não é um exemplo de 'correção' da linguagem. É uma questão simples decorrente do fato de as linguagens terem objetivos de design muito diferentes.

O objetivo de C era ser uma linguagem próxima à máquina que pudesse ser usada para implementar sistemas operacionais. Máquinas (principalmente) não suportam números decimais de precisão infinita. Máquinas (principalmente) possuem números inteiros de comprimentos de bits fixos.

Dave
fonte