Estou interessado na ideia de C ++ - const
não como aquela execução específica (como jogar fora const
).
Tomemos, por exemplo, C # - falta const, como C ++, e o motivo é o habitual - pessoas e tempo. Aqui, além disso, parece que a equipe do C # analisou a execução do C ++ no const
marketing de CLR e já tinha o suficiente neste momento (veja por que não há um método membro const no parâmetro c # e const ; obrigado Svick). Seja se formos mais longe do que isso, há mais alguma coisa?
Existe algo mais profundo? Tomemos, por exemplo, a herança múltipla - geralmente é vista como difícil de entender (para o usuário) e, portanto, não é adicionada ao idioma (como o problema do diamante).
Há algo em NATUREZA do const
que representar um problema que é melhor para a linguagem para evitá-lo? Algo como decidir se const
deve ser profundo ou superficial (ter const
contêiner significa que não posso adicionar novos elementos nem alterar elementos existentes; e se os elementos forem do tipo de referência)?
ATUALIZAÇÃO : enquanto menciono C #, e, portanto, criando uma perspectiva histórica, estou interessado na natureza dos possíveis problemas do const
idioma.
Este não é um desafio das línguas. Ignore fatores como tendências atuais ou popularidade - só estou interessado em questões técnicas - obrigado.
fonte
Respostas:
Observe se isso se qualifica para você, mas em idiomas funcionais como o ML padrão tudo é imutável por padrão. A mutação é suportada por meio de um
ref
tipo de essência genérico . Portanto, umaint
variável é imutável e umaref int
variável é um contêiner mutável paraint
s. Basicamente, variáveis são variáveis reais no sentido matemático (um valor desconhecido, mas fixo)ref
es são "variáveis" no sentido imperativo da programação - uma célula de memória que pode ser escrita e lida. (Gosto de chamá-los de atribuíveis .)Eu acho que o problema
const
é duplo. Primeiro, o C ++ não possui coleta de lixo, o que é necessário para ter estruturas de dados persistentes não triviais .const
deve ser profundo para fazer algum sentido, mas ter valores totalmente imutáveis em C ++ é impraticável.Segundo, em C ++ você precisa optar por
const
não optar por sair dele. Mas quando você se esquece deconst
algo e depois o corrige, você acabará na situação "const envenenamento" mencionada na resposta do @ RobY, onde aconst
mudança ocorrerá em cascata no código. Seconst
fosse o padrão, você não se aplicariaconst
retroativamente. Além disso, ter que adicionar emconst
qualquer lugar adiciona muito ruído ao código.Eu suspeito que as principais linguagens que se seguiram (por exemplo, Java) foram fortemente moldadas pelo sucesso e pela maneira de pensar de C e C ++. Caso em questão, mesmo com a coleta de lixo, a maioria das APIs de coleta de idiomas assume estruturas de dados mutáveis. O fato de tudo ser mutável e a imutabilidade ser visto como um caso de canto fala muito sobre a mentalidade imperativa por trás das línguas populares.
EDIT : Depois de refletir sobre o comentário de greenoldman, percebi que
const
não se trata diretamente da imutabilidade dos dados;const
codifica no tipo do método se tem efeitos colaterais na instância.É possível usar a mutação para obter um comportamento referencialmente transparente . Suponha que você tenha uma função que, quando chamada, retorne sucessivamente valores diferentes - por exemplo, uma função que lê um único caractere
stdin
. Poderíamos usar cache / memorizar os resultados dessa função para produzir um fluxo de valores referencialmente transparente. O fluxo seria uma lista vinculada cujos nós chamarão a função na primeira vez que você tentar recuperar seu valor, mas depois armazenará em cache o resultado. Portanto, sestdin
considerarHello, world!
, na primeira vez que você tentar recuperar o valor do primeiro nó, ele lerá umchar
e retornaráH
. Depois disso, ele continuará retornandoH
sem mais chamadas para ler achar
. Da mesma forma, o segundo nó leria umchar
destdin
a primeira vez que você tenta recuperar seu valor, dessa vez retornandoe
e armazenando em cache esse resultado.O interessante aqui é que você transformou um processo inerentemente estável em um objeto aparentemente sem estado. No entanto, foi necessário alterar o estado interno do objeto (armazenando os resultados em cache) para conseguir isso - a mutação foi um efeito benigno . É impossível fazer o nosso,
CharStream
const
mesmo que o fluxo se comporte como um valor imutável. Agora imagine que há umaStream
interface comconst
métodos, e todas as suas funções esperamconst Streams
. VocêCharStream
não pode implementar a interface!( EDIT 2: Aparentemente, existe uma palavra-chave C ++ chamada
mutable
que nos permite trapacear e criarCharStream
const
. No entanto, essa brecha destróiconst
as garantias - agora você realmente não pode ter certeza de que algo não sofrerá alterações por meio de seusconst
métodos. Suponho que não seja isso. ruim, pois você deve solicitar explicitamente a brecha, mas ainda depende totalmente do sistema de honra.)Em segundo lugar, suponha que você tenha funções de alta ordem - ou seja, você pode passar funções como argumentos para outras funções.
const
ness faz parte da assinatura de uma função, portanto você não seria capaz de passar não-const
funções como argumentos para funções que esperamconst
funções. Aplicar cegamenteconst
aqui levaria a uma perda de generalidade.Finalmente, manipular um
const
objeto não garante que ele não esteja alterando algum estado externo (estático ou global) pelas suas costas, portantoconst
as garantias não são tão fortes quanto parecem inicialmente.Não está claro para mim que codificar a presença ou ausência de efeitos colaterais no sistema de tipos é universalmente uma coisa boa.
fonte
var
sob demanda deixaria apenas um problema - a profundidade?const
referência a um não-const
objeto. Mesmo assim, não acredito que faça sentido ter uma superficialidadeconst
. O ponto principalconst
é a garantia de que você não poderá modificar o objeto por meio dessa referência. Você não tem permissão para contornarconst
criando uma nãoconst
referência, então por que seria correto contornarconst
alterando os membros do objeto?func foo(const String &s)
e este é um sinals
que não será alteradofoo
.null
e herança.)O principal problema é que os programadores tendem a não usá-lo o suficiente, então, quando atingem um local onde é necessário, ou um mantenedor mais tarde deseja corrigir a correção constante, há um enorme efeito cascata. Você ainda pode escrever um código imutável perfeitamente bom sem
const
, seu compilador simplesmente não o aplicará e terá mais dificuldade em otimizá-lo. Algumas pessoas preferem que seu compilador não as ajude. Eu não entendo essas pessoas, mas existem muitas.Nas linguagens funcionais, praticamente tudo é
const
, e ser mutável é a rara exceção, se é permitido. Isso tem várias vantagens, como concorrência mais fácil e raciocínio mais fácil sobre o estado compartilhado, mas leva algum tempo para se acostumar se você vem de um idioma com uma cultura mutável. Em outras palavras, não quererconst
é uma questão de pessoas, não técnica.fonte
Vejo os inconvenientes como:
"envenenamento const" é um problema quando uma declaração de const pode forçar uma declaração anterior ou seguinte a usar const, e isso pode fazer com que suas declarações anteriores a seguir usem const, etc. E se o envenenamento const fluir para uma classe em uma biblioteca que você não tem controle, pode ficar preso em um lugar ruim.
não é uma garantia absoluta. Geralmente, há casos em que o const apenas protege a referência, mas é incapaz de proteger os valores subjacentes por um motivo ou outro. Mesmo em C, existem casos extremos que a const não pode alcançar, o que enfraquece a promessa que a const oferece.
em geral, o sentimento da indústria parece estar se afastando de fortes garantias em tempo de compilação, por mais conforto que elas possam trazer a você e a mim. O cara lançou 10 módulos Python perfeitamente funcionais, bem projetados, bem testados e totalmente funcionais. E ele nem estava hackeando quando fez isso.
Então, talvez a pergunta seja: por que levar adiante um recurso potencialmente controverso sobre o qual até alguns especialistas são ambivalentes quando você está tentando obter a adoção de seu novo e sofisticado idioma?
EDIT: resposta curta, um novo idioma tem uma colina íngreme para subir para adoção. Os designers realmente precisam pensar muito sobre os recursos necessários para obter adoção. Pegue o Go, por exemplo. O Google meio que brutalmente truncou algumas das mais profundas batalhas religiosas ao fazer algumas escolhas de design ao estilo Conan-Bárbaro, e acho que a linguagem é melhor para ela, pelo que vi.
fonte
int *
ponteiro mutável para valor mutável,int const *
ponteiro mutável para valorint * const
const , ponteiro const para valor mutável,int const * const
ponteiro const para valor const.const
), portanto, essas "razões" considero irrelevantes (pelo menos para essa pergunta). Sobreconst
envenenamento - você pode dar um exemplo? Porque AFAIK é a vantagem, você passa algoconst
e deve permanecerconst
.const
problema, mas mudar realmente o tipo - faça o que fizer, sempre será um problema. Considere passarRichString
e depois perceber que é melhor passarString
.const
. É muito fácil ignorar asconst
coisas que deveriam ser,const
porque você precisa optar por isso em vez de desistir.Existem alguns problemas filosóficos em adicionar
const
a um idioma. Se você declararconst
para uma classe, isso significa que a classe não pode mudar. Mas uma classe é um conjunto de variáveis acopladas a métodos (ou mutadores). Atingimos a abstração ocultando o estado de uma classe atrás de um conjunto de métodos. Se uma classe é projetada para ocultar o estado, é necessário que os mutadores mudem esse estado de fora e, então, não éconst
mais. Portanto, só é possível declararconst
para classes que são imutáveis. Portanto,const
parece apenas possível em cenários em que as classes (ou os tipos que você deseja declararconst
) são triviais ...Então, precisamos
const
mesmo assim? Acho que não. Eu acho que você pode facilmenteconst
ficar sem se tiver um bom design. Quais dados você precisa e onde, quais métodos são métodos de dados a dados e quais abstrações você precisa para E / S, rede, exibição etc. Então você naturalmente divide módulos e classes que lidam com estado e você tem métodos e métodos. classes imutáveis que não precisam de estado.Eu acho que a maioria dos problemas surge com objetos de dados grandes e gordurosos que podem salvar, transformar e desenhar a si mesmos, e então você deseja passá-los para um renderizador, por exemplo. Portanto, você não pode copiar o conteúdo dos dados, porque isso é muito caro para um grande objeto de dados. Mas você também não quer que isso mude, então precisa de algo como
const
pensa. Deixe o compilador descobrir suas falhas de design. No entanto, se você dividir esses objetos em apenas um objeto de dados imutável e implementar os métodos no módulo responsável, poderá distribuir (apenas) o ponteiro e fazer o que deseja com os dados, além de garantir a imutabilidade.Eu sei que é possível em C ++ declarar alguns métodos
const
e não declarar em outros métodos, porque eles são mutadores. E, algum tempo depois, você precisa de um cache e, em seguida, um getter modifica um objeto (porque ele carrega lentamente) e não éconst
mais. Mas esse era o objetivo dessa abstração, certo? Você não sabe qual estado é alterado a cada chamada.fonte
const
(no sentido de C ++ ) você deve definir a interface, também para todas as propriedades.