Rust: var palavra-chave apenas para locais mutáveis

Criado em 20 jun. 2012  ·  35Comentários  ·  Fonte: rust-lang/rust

A edição # 1273 propôs let mut para locais mutáveis ​​e mut para campos mutáveis. let mut é mais detalhado do que uma única palavra-chave e também quebra o alinhamento da coluna. As pessoas corretamente não gostaram da ideia de var para declarações de campos mutáveis. Mas acho que ninguém sugeriu a ideia de usar var para declarações locais mutáveis ​​e mut para declarações de campos mutáveis:

let x = 7; // declaration of immutable variable x
var y = 7; // declaration of mutable variable y
type point = { mut x: int, mut y: int }; // declaration of mutable record type

Dave

I-nominated

Todos 35 comentários

Tenho que confessar, a princípio pensei que deveríamos usar a mesma palavra-chave para vars mutáveis ​​e campos mutáveis, mas var lê meio bem (embora eu não goste de let mut )

Eu acho que é um recurso que declarar uma variável mutável é ligeiramente mais complicado do que uma variável imutável. Posso ver os programadores usando apenas "var" para serem "consistentes" ou porque "var" seria mais poderoso (não é necessário alterá-lo se você decidir fazer uma mutação posteriormente). Então você acaba com um código menos legível em geral.

Não sugerindo que Rust deva ser uma linguagem séria de escravidão e disciplina, mas um leve empurrão na direção certa é moralmente justificável, eu acho (ou seja, a regra seria "para código seguro, as construções mais seguras devem ser menos barulhentas que as mais poderosas, mas construções mais fáceis de bagunçar ").

Por um lado, gosto disso, pois removeria a ambigüidade visual deste formulário:

let mut x = 4,
    y = 8;  // is y mutable or not?

Mas estou inclinado a ficar do lado do ssylvan. Declarar mutáveis ​​não precisa ser exatamente _fugamente_, mas acho que faz sentido se eles forem um pouco menos convenientes de criar do que os imutáveis, mesmo que apenas com um único toque de tecla. A palavra-chave de ativação também precisa ser distinta e (IMO) var é amplamente usada como uma palavra-chave de declaração de variável genérica para transmitir especificamente mutabilidade em uma linguagem que se orgulha de imutabilidade por padrão. E pense nos pobres programadores de C #, para quem var é o nosso let !

Ainda gosto da ideia de substituir let mut por uma única palavra-chave, de modo a abordar o trecho de código acima, mas há alguma razão para introduzir uma nova palavra-chave quando mut si só seria suficiente, conforme a proposta original em # 1273?

@pcwalton apontou um problema com apenas o uso de mut : há uma ambigüidade com literais de registro e expressões de bloco que requer uma análise antecipada arbitrária para ser resolvida.

{ mut x: int ...

Literal de registro ou bloco com variável local?

Eu pude ver muitos programadores apenas aprendendo que var é como você declara variáveis ​​no Rust, e não usando let alguma. Afinal, var é como você declara variáveis ​​locais em linguagens como JavaScript. Estou inclinado a pensar que isso é uma coisa boa sobre esta proposta.

Eu ouvi alguém dizer ontem que agora let e var teriam o mesmo comprimento, o que seria bom para o alinhamento.

Sou um tanto indiferente, mas prefiro var , porque é mais curto. Tornar a mutabilidade irritante não é um objetivo desejável, a meu ver. (Na verdade, tendo a pensar que o papel de uma linguagem de programação não deve ser o de fazer nada chato - apenas _claro_, o que não é a mesma coisa.)

Embora eu ainda esteja receoso de usar let e var juntos (como Javascript, mas 100% diferente), seria muito menos problemático se houvesse uma passagem de lint para detectar variáveis que são declarados como mutáveis, mas nunca realmente sofreram mutação.

Existe um plano para tornar a mutabilidade uma parte do tipo. Isso afeta os locais e torna isso irrelevante?

E se:

val x = ... // immutable (val-ue)
var y = ... // mutable (var-iable)

Como no Scala.

Acho que @brson está certo e esse problema desaparece quando movemos mut para um tipo, ou seja, você obtém let x = mut 10;

Fechando esta questão por enquanto; reabra se achar que estou errado!

Eu não tenho certeza sobre isso. Gosto da ideia de mudar o mut para o tipo, mas não sei se é um "negócio fechado" --- pode haver estranheza persistente aí. Em qualquer caso, nunca pensei que alguém pudesse escrever let x = mut 5 , sempre achei que você escreveria let mut x = 5 exatamente como hoje; a "mutabilidade" do tipo de uma variável viria da maneira como ela foi declarada, não do valor que está sendo atribuído a ela.

Fazer o contrário pareceria implicar que, se você tiver um array x do tipo [mut int] e escrever let y = x[0] então y é mutável? Ou alguma coisa? Isso parece indesejável.

@Dretch Eu não amo val / var porque eles não são distintos o suficiente, embora o precedente Scala seja bom.

Compartilho a preocupação de @eholk sobre as pessoas aprenderem a usar var por padrão. Do jeito que funciona agora, tendo a declarar tudo como imutável, então o compilador me lembra que deve ser mutável, então eu digito mut . Este é um comportamento indiscutivelmente bom que você estaria menos inclinado a ter com uma divisão de var/let - digitar var e let são igualmente difíceis, mas você não pode nem mesmo digitar let mut sem digitar let .

Mas não tenho preferência e agradeço quando posso compor funções inteiramente de declarações que começam com palavras-chave de três caracteres.

@nikomatsakis Em particular, faz sentido para mim que as regras sobre atribuição única devam vir da mutabilidade da declaração, e não do tipo. Alterar sutilmente as regras de atribuição com base no tipo parece engraçado para mim.

Estou inclinado a concordar com @pcwalton que não devemos penalizar os programadores por usarem uma ligação mutável se isso é o que eles querem. Quanto à preocupação com as pessoas usando var desnecessariamente, poderíamos adicionar um aviso opcional que reclamaria se uma ligação var fosse atribuída individualmente. Mas também acho que podemos abrir precedentes para um bom estilo no rustc e na biblioteca padrão.

Dave

É realmente terrível se os programadores declararem todas as suas variáveis ​​mutáveis? Parece que não é o fim do mundo se temos um conjunto de programadores Rust que pensam apenas que var é como você declara variáveis ​​e outro conjunto que entende usar let maioria das vezes e var quando necessário. Como os primeiros programadores do Rust, podemos abrir o precedente a favor do uso de let e var corretamente.

O bom design de sintaxe da IMHO não se trata apenas de tornar conveniente "tudo" que você pode querer fazer, é sobre empurrar gentilmente as pessoas para o "caminho suave" da semântica e objetivos de design da linguagem.

Por exemplo, você provavelmente não adicionaria suporte sintático especial para listas vinculadas em Rust (a la Haskell), porque um dos princípios fundamentais de Rust é ser eficiente, e o uso generalizado de listas vinculadas funcionará de forma contrária a esse princípio. Pela mesma razão, compartilhar dados mutáveis ​​entre threads provavelmente não deveria ser muito conveniente (já que a simultaneidade segura é outro princípio), nem deveria ser superconveniente lançar um int arbitrário para um ponteiro (já que a segurança da memória é um grande princípio).

Não quer dizer que deveria ser impossível fazer qualquer uma dessas coisas, veja, apenas proporcionalmente inconveniente, de modo que fica claro na sintaxe qual é a forma idiomática de escrever Rust.

Variáveis ​​mutáveis ​​(locais) não são tão ruins quanto qualquer uma dessas, mas se Rust está de fato favorecendo dados imutáveis ​​por motivos de correção e manutenção (algo com que eu pessoalmente concordo), então a sintaxe idealmente deveria dar um leve empurrão nessa direção. Mesmo um único caractere extra ou um sigilo modificador extra ou qualquer outra coisa seria o suficiente para deixar claro que "let" é menos complicado do que "let mut" ou "let!" ou qualquer outra coisa e, portanto, deve ser o padrão preferido que você deve tentar quando não precisar que a variável seja mutável.

@ssylvan Oh, entendo esse ponto, é apenas uma questão de grau e de equilíbrio de compensações. Já promovemos a imutabilidade das estruturas de dados, e os locais imutáveis ​​da IMO são menos importantes de promover do que os campos imutáveis. (Especialmente porque, IINM, não permitimos que locais mutáveis ​​escapem em fechamentos de heap.) E a perda da capacidade de refatorar entre let e var sem alterar a contagem de colunas supera o benefício de promovendo locais imutáveis. Difícil de quantificar, então acho que é apenas meu sentimento.

Dave

Bem, nesse caso, pelo menos "let foo = mut bar" ou "let foo: = bar" em oposição a "let mut foo = bar" faria o primeiro token se alinhar. Presumivelmente, o nome da variável terá comprimento variável, portanto, não é tão importante evitar modificadores extras no resto da instrução.

Oh, ei, eu meio que parcial para a ideia := .

Dave

Pensando bem, Pascal é permanentemente chato. Eu retiro. :)

Dave

Além disso, let foo := bar evita algo assim:

let mut foo;
foo = bar;

Achei esse padrão útil às vezes, embora pareça que provavelmente sempre haja outra maneira de escrever o mesmo padrão.

@eholk , não acho que isso impeça. Mas ainda acho que parecerá muito estranho para programadores de quase todas as linguagens convencionais.

Dave

Com relação a := , Go o usa para indicar atribuição inferencial de tipo (embora ainda não seja uma linguagem comum). Mas posso prever a dificuldade em distinguir entre as duas formas à primeira vista:

let foo = "hello";
let foo := "hell";

O argumento de brson para a sintaxe atual (ou seja, que a declaração mutável requer primeiro a declaração imutável) é convincente. É totalmente ótimo se as linguagens de programação forem opinativas, contanto que não sejam idiotas sobre isso. :)

Não estou interessado em = vs. := . Principalmente oposto a val , var e suas variações; simplesmente não é _obvio_ que ele controla a mutabilidade. Quer dizer, não vou desistir com nojo se adotarmos um deles, mas acho que "precisar explicar o mnemônico" é um mau sinal. Estou mais ok com:

  • Deixando o tipo ditar.
  • Permitir que mut sozinho trabalhe como um declarador local e exigindo que o analisador atrase a confirmação da sintaxe de registro vs. declaração local de um token extra; ainda é LL (1) é apenas adiciona um estado gramatical intermediário extra, sem retrocesso extra (ambos os caminhos a seguir são válidos).
  • Deixando como let mut .

O principal motivo para evitar locais mutáveis ​​"acidentais" é que introduzimos a captura de ambiente, de modo que eles se transformam em uma forma de ação à distância, bem como riscos para uma variedade de análises, como empréstimo.

(Todos os lets eram inicialmente mutáveis, mas também não tínhamos captura de ambiente, apenas vinculação. Agora não temos vinculação, apenas captura de env. Tomayto, tomahto.)

Acredito que mutáveis ​​não podem ser capturados implicitamente agora.

@graydon está correto ao dizer que houve duas motivações originais. No entanto, apenas um ainda é relevante. As duas motivações foram

  • captura implícita "por cópia" de variáveis ​​mutáveis ​​em um fn@
  • entender quais dados são mutáveis ​​e quais não são para empréstimo

Acontece que o último não é mais relevante. O uso de variáveis ​​mutáveis ​​/ imutáveis ​​era muito grosseiro na prática, então borrowck teve a ideia de emprestar uma variável "temporariamente" --- uma variável mutável pode ser emprestada com um ptr imutável, desde que a variável não seja modificada enquanto o ponteiro estiver em alcance.

Poderíamos talvez apenas remover a ideia de locais mutáveis ​​/ imutáveis ​​e voltar à regra antiga --- tudo é mutável. Poderíamos então emitir avisos quando uma variável que é copiada implicitamente em um fechamento é modificada depois que o fechamento é criado.

Há uma terceira motivação: variáveis ​​imutáveis ​​são mais fáceis de raciocinar. Se tudo for mutável, você terá que examinar toda a função para ver quais valores uma variável pode ter durante seu tempo de vida. Cada variável tem potencialmente um fluxo de dados complicado (especialmente com loops, ramos, parâmetros de função mutáveis, etc.) e é difícil ver o que está acontecendo sem analisar cuidadosamente cada instrução. Se você tem apenas um ou dois mutáveis ​​em uma função, ele age como um "sinalizador" para que você seja mais cuidadoso ao ler o código que envolve a bainha.

@Dretch Também gosto do estilo Scala, com palavras-chave "val" e "var".

Gosto de como a sintaxe atual faz com que os mutáveis ​​se projetem como um polegar machucado; torna a digitalização do código mais fácil. val e var parecem muito semelhantes visualmente nesse aspecto. O que não quer dizer que mutáveis ​​absolutamente _ devam_ sobressair, mas manter as palavras-chave visualmente distintas é uma faceta importante da usabilidade.

Eu entendo que os campos mutáveis ​​serão removidos da ferrugem. Isso significa que mut poderia ser usado em vez de let mut porque a ambigüidade do registro / variável no bloco desapareceria?

Também acredito que os registros estruturais estão indo, o que remove a ambigüidade mesmo se os campos mutáveis ​​permanecerem.

@Dretch é verdade que os campos mutáveis ​​estão desaparecendo e os registros estruturais já foram eliminados.

Eu sou indiferente ao problema, embora eu gostaria de apontar que _pode_ fazer sentido para mut ser uma palavra-chave de declaração por si só (como Dretch propõe), no caso de congelamento / descongelamento . Compare hoje:

let foo = 1;  // immutable
/* 10,000 lines of code here */
let mut foo = foo;  // we're making foo mutable, totally understandable
/* 10,000 lines of code here */
let foo = foo;  // potential wtf

Com a proposta:

let foo = 1;  // immutable
/* 10,000 lines of code here */
mut foo = foo;  // a mutable foo, no problems here
/* 10,000 lines of code here */
let foo = foo;  // slightly less of a potential for wtf, since we officially have two declaration forms

Embora eu também sinta que isso tornaria o Rust-ismo "ausência de mut implica imutabilidade" menos consistente, porque ainda estaríamos escrevendo let foo = 1; vez de apenas foo = 1; (a última forma é obviamente indesejável para declaração).

Kotlin também usa val e var .

Não acho que faremos essa alteração, mas indicarei para o marco 1, bem definido, para que possamos resolver.

consenso é não fazer isso, pois é incompatível com a mudança de mut para associações de padrão. fechando.

Esta página foi útil?
0 / 5 - 0 avaliações

Questões relacionadas

pedrohjordao picture pedrohjordao  ·  3Comentários

modsec picture modsec  ·  3Comentários

mcarton picture mcarton  ·  3Comentários

zhendongsu picture zhendongsu  ·  3Comentários

drewcrawford picture drewcrawford  ·  3Comentários