Rust: (Módulos) Problema de rastreamento para `crate` como um modificador de visibilidade

Criado em 6 ago. 2018  ·  91Comentários  ·  Fonte: rust-lang/rust

Este é um problema de sub-rastreamento para o RFC "Esclarecer e simplificar caminhos e visibilidade" (rust-lang/rfcs#2126)
lidando com a questão de crate como um modificador de visibilidade.

Perguntas não resolvidas:

  • [ ] Como analisamos struct Foo(crate ::bar) ?
A-visibility B-RFC-approved B-RFC-implemented B-unstable C-tracking-issue T-lang

Comentários muito úteis

Pessoalmente, estou bem em escrever pub(crate) , a intenção parece muito explícita.
O exemplo dado por @johnthagen é realmente doloroso de ver (usando crate ):

use crate::menu::{Sound, Volume};

crate mod color;

...

/// A type for storing text and an associated color it should
/// be drawn as.
crate struct ColoredText {
    crate color: types::Color,
    crate text: &'static str,
}

crate mod color; especialmente parece confuso, você definitivamente precisa pensar um pouco sobre o que está acontecendo lá.

Todos 91 comentários

Comentários sobre crate como modificador de visibilidade:

Análise de ambiguidade

Antinatural / Confusão / Não melhora

Uma boa ideia

pub(extern) em vez disso

Garagem de bicicletas

Uma prévia antecipada

Tópico dedicado

Pessoalmente, sou muito a favor de crate como modificador de visibilidade e compartilho o comentário de @stepancheg aqui . Acho que devemos encorajar visibilidades menores e mais restritas e crate faz exatamente isso.

Pessoalmente, estou bem em escrever pub(crate) , a intenção parece muito explícita.
O exemplo dado por @johnthagen é realmente doloroso de ver (usando crate ):

use crate::menu::{Sound, Volume};

crate mod color;

...

/// A type for storing text and an associated color it should
/// be drawn as.
crate struct ColoredText {
    crate color: types::Color,
    crate text: &'static str,
}

crate mod color; especialmente parece confuso, você definitivamente precisa pensar um pouco sobre o que está acontecendo lá.

Alguns desses exemplos são muito C- static -esque- intuitivamente relacionados, mas realmente surpreendentemente distintos.

O exemplo devido a @johnthagen não me lê mal. Na verdade, ele lê naturalmente e eu gosto bastante da simetria. É bonito de certa forma.

Se a legibilidade de:

crate struct ColoredText {
    crate color: types::Color,
    crate text: &'static str,
}

torna-se um problema; então um IDE/editor que entenda a sintaxe do Rust pode destacar os tokens crate nas diferentes posições com cores diferentes. Isso deve esclarecer bem a diferença, eu acho.

crate como modificador de visibilidade é definitivamente estranho: ele usa uma palavra-chave muito específica para ferrugem para uma coisa que não é específica para ferrugem. Kotlin e C# usam internal para isso.

Eu pessoalmente gostaria de reutilizar pub para crate-visible , e optar por uma sintaxe mais gritante para visibilidade mundial, como pub* ou pub! .

Já foi mencionado antes, mas acho que os problemas de raiz que vejo são:

  1. crate e um substantivo . Eu acho que pub(crate) é longo e estranho, então eu apoio totalmente substituí-lo por algo , mas ele tinha o adjetivo público associado a ele, então gramaticalmente fluiu melhor.
  2. crate agora é usado como âncora para importações "this-crate", o que significa algo diferente de "onde quer que isso seja definido, também é exportado visivelmente desta caixa"
// Here `crate` means the root of this crate.
use crate::menu::{Sound, Volume};

// Here, `crate` means: export crate::game::color
// The `crate` is referring to `color`, not the root.
crate mod color;

...

/// A type for storing text and an associated color it should
/// be drawn as.
// Same potential confusion as `crate mod color`
crate struct ColoredText {
    crate color: types::Color,
    crate text: &'static str,
}

Comparado a um exemplo, usando o internal de @matklad do Kotlin/C#.

use crate::menu::{Sound, Volume};

internal mod color;

...

/// A type for storing text and an associated color it should
/// be drawn as.
internal struct ColoredText {
    internal color: types::Color,
    internal text: &'static str,
}

Não estou dizendo que internal é a palavra-chave certa (Rust gosta de abreviações muito curtas e int infelizmente está cheio de confusão C/C++/Java), mas pessoalmente acho que o segundo exemplo é imediatamente mais legível.

Eu também acho que a palavra-chave de visibilidade crate será confusa para as pessoas que chegam ao Rust de outros idiomas. Se até mesmo muitos de nós envolvidos o suficiente em Rust para comentar sobre esses tópicos estão confusos, eu teria que imaginar que isso também fará com que pessoas novas em Rust também.

A sintaxe um pouco mais longa de pub(crate) pode não ser um grande problema se não estivesse se tornando um aviso/erro para ter pub itens que não podem ser alcançados fora da caixa. Eu pessoalmente gostaria que se eu tivesse um pub(crate) struct Foo { ... } , que o compilador pudesse perceber que todos os pub fn s em um impl Foo são claramente inalcançáveis ​​e não me incomodam com isso.

Acho que é apenas um trabalho ocupado atualmente no Rust 2015 se eu marcar um tipo de pub struct Foo a pub(crate) struct Foo , como o compilador grita em todos os lugares que alguns outros pub fn s existem usando o tipo pub(crate) repente, quando o problema não é real, porque o outro tipo também é pub(crate) .

Eu também acho a ideia do @matklad de reaproveitar pub como caixa-pública e usar export ou algo para exportações visíveis no mundo. Mas isso pode ser uma divergência muito grande para uma edição?

Reaproveitar pub como crate-public e adicionar uma nova visibilidade para world-public era a proposta antes da versão atual. Tal mudança na semântica existente foi considerada muito drástica mesmo para uma edição, e é por isso que pub agora mantém seu significado atual.

O que foi menos discutido e considerado, eu acho, foi redirecionar pub apenas por meio de um fiapo. Talvez pudéssemos mudar o lint de "avisar pub que não está acessível fora da caixa" para "avisar pub que está acessível fora da caixa" e adicionar um pub(extern) puramente opcional pub(extern) / export palavra-chave. Ou seja, não altere nenhuma semântica, apenas adicione uma sintaxe de silenciamento de lint.

Suspeito que isso seria menos perturbador, com base na suposição de que há menos itens públicos mundiais do que itens públicos da caixa. Também preservaria o significado intuitivo (embora sutilmente incorreto) de pub como "exportação do módulo atual" em vez de confrontar todos com o verdadeiro comportamento da visibilidade.

Rust gosta de abreviações muito curtas, e int infelizmente está cheio de confusão C/C++/Java

FWIW, embora salve apenas dois caracteres, se quiséssemos abreviar internal , a abreviação "certa" provavelmente seria, por analogia com extern al, intern . Infelizmente, esse também é um substantivo com um significado diferente e comumente entendido. Ah bem.

@glaebhoerl intern é uma boa opção a considerar! ❤️

A simetria com extern é muito boa, e a IMO reduziria bastante a confusão potencial com a forma substantiva de intern .

É curto (apenas 1 caractere a mais que crate ) e não entra em conflito com use crate:: .

O exemplo atualizado ficaria assim:

use crate::menu::{Sound, Volume};

intern mod color;

...

/// A type for storing text and an associated color it should
/// be drawn as.
intern struct ColoredText {
    intern color: types::Color,
    intern text: &'static str,
}

Já mencionei isso antes, mas não tenho certeza de qual é o problema com substantivos usados ​​como adjetivos?

Para recapitular: há muitos substantivos que podem ser usados ​​como adjetivos, por exemplo. um gato doméstico, um mouse de computador, uma mesa de computador, etc... Uma busca no Google por _substantivos ingleses usados ​​como adjetivos_ parece indicar que não há nada inerentemente errado, embora nem todos os substantivos funcionem como adjetivos.

Vamos tentar:

_crate mod hello;_ Um módulo de crate chamado hello, parece bom.
_crate fn world() {}_ Uma função de crate chamada world, parece boa.
_crate struct Foo;_ Um engradado struct chamado Foo, parece bom.
_crate enum Bar {}_ Um crate enum chamado Bar, parece bom.
_traço de engradado Baz {}_ Um traço de caixote chamado Baz, se sente bem.

_crate use self::local::Foo;_ Ack, esse aqui não funciona, um engradado usa? Você pode lê-lo como um item utilizável de caixa chamado Foo. Isso quebra o padrão.

Também pode ser estranho quando usado na frente de membros de estrutura e ainda mais em combinação com a caixa como a raiz de um caminho.

Embora o engradado não seja perfeito, não estou convencido de que 'ser um substantivo' seja um fator decisivo.

O problema é que é muito incomum. Não há nenhuma linguagem de programação que eu conheça que use substantivos como modificador de tipo.

@Centril

torna-se um problema; então, um IDE/editor que entenda a sintaxe do Rust pode destacar os tokens da caixa nas diferentes posições com cores diferentes. Isso deve esclarecer bem a diferença, eu acho.

Pessoalmente, embora eu ache boas características de diferentes editores, não acho que devemos projetar a linguagem com a suposição de um editor suficientemente avançado. Eu senti que o C# foi projetado dessa maneira e foi um fator importante na minha frustração com essa linguagem.

@epage Acho que crate como modificador de visibilidade é uma boa ideia, independentemente do destaque; Estou apenas sugerindo que o destaque é uma mitigação adicional . Em particular, deve ser bastante trivial para qualquer editor destacar crate:: de forma diferente de crate field porque o primeiro é sempre crate + :: que é fácil de verificar para em todos os casos, exceto crate ::foo::bar (mas isso será bastante raro...).

Como uma pessoa do IDE, acho que esse destaque adicionaria uma quantidade significativa de ruído para uma quantidade muito pequena de informações, gerando um resultado negativo. IMO (isso é altamente pessoal, mas informado pelo uso e implementação de IDEs poderosos) o destaque funciona melhor quando transmite informações semânticas não locais (esse uso se refere a uma variável que foi declarada com mut ) e enfatiza aspectos locais "boilerplaty" do código (portanto, todas as palavras-chave devem ter o mesmo estilo).

Parece-me que dom (ou seja: doméstico) é um candidato em potencial.

Ele tem três letras (bom para alinhamento, fácil de lembrar), não é um substantivo e - além de 'Document Object Model' - não acho que tenha nenhuma ambiguidade específica anexada a ele.

pub struct MyStruct {
    dom num: i32,
    pub msg: String,
}

Alguém tem pensamentos sobre isso?

Um ângulo sobre isso que eu vi mencionado, mas não consegui encontrar no resumo (obrigado por fazer isso!) é como um atalho se encaixa na sintaxe pub() existente.

Se pub e <something> (por exemplo crate ) têm um significado especial, isso reduz ainda mais a visibilidade e, por extensão, a familiaridade de pub(<something>) . Seja qual for a solução que escolhermos, acho que ela deve apoiar ou substituir o maquinário existente, em vez de ser mais um.

Por exemplo, se usarmos crate ou substituição:

  • O crate deve ser estendido para atender às restrições de escopo (por exemplo crate(<something>) )?
  • Devemos depreciar pub() para que pub tenha apenas um significado?

Considerando isso e meu entendimento do objetivo (esclarecer a API pública da API interna), me levou a recriar a ideia do @vitiral de pub(extern) .

  • Se encaixa dentro de máquinas existentes
  • imo melhora a maquinaria existente tornando pub um atalho de pub(<something>) em vez de ser um caso especial
  • Se a API pública for significativamente menor que a API privada, então ponderamos a sintaxe da maneira correta.
  • Mas pode confundir pessoas vindas de outros idiomas onde public significa que pode estar em sua API pública.

RE Impacto no encapsulamento

Um benefício do sistema pub existente é o encapsulamento. O caminho mais fácil é expor a API apenas um nível acima. Isso torna mais fácil ter coisas públicas para partes de uma caixa, mas privadas para toda a criação.

Embora ainda haja pub(super) , ter um atalho para pub(crate) levará as pessoas a usá-lo mais, incentivando as pessoas a não encapsular suas APIs.

Eu suspeito que isso não é um problema por causa da cultura de pequenas caixas.

Mas ao considerar isso, isso me dá outra iteração no meu comentário acima em pub(extern)

  • pub deveria ser um atalho para pub(super)
  • pub(extern) é necessário para sua API pública.

Anteriormente, mencionei a preocupação de pessoas em transição de outros idiomas. Isso se alinha melhor com eles.

  • Corresponde mais de perto como public funciona em vários idiomas
  • Algumas linguagens tendem a ter um mecanismo distinto para API pública, então isso é explicável para elas.

imo este é o melhor de todos os mundos. Então rasgue-o e me ajude a entender por que não :)

Eu ainda odeio a sintaxe pub(foo) . Hiperbolicamente, parece que não pode decidir se é uma chamada de função ou um mashup de várias palavras-chave. Nós não usamos let(mut) ou for(in) então qual é o problema com este?

@parasyte pub<foo> pela vitória! Afinal, não é um _tipo de visibilidade_?

pub<crate> ou pub(crate) sentem-se realmente melhor.

Alguns pensamentos de alguém que mudou de acampamento:

No começo eu era muito contra crate e pensei "isso está arruinando o bom pub ".

Eu então tentei lado a lado em alguns dos meus projetos e deixei-o afundar.

Francamente, depois de alguns dias eu não aguentava mais olhar para pub(X) , parece desajeitado em comparação e mais difícil de ler.

Inicialmente, temi que pudesse haver ambiguidade (visual); mas comigo aconteceu o contrário: se eu vejo crate agora eu sei que é, bem, "coisas de caixote". Seja importando módulos ou declarando visibilidade. O que exatamente é na esmagadora maioria dos casos muito claro a partir do contexto (como a ambiguidade em inglês).

Eu posso ver que ainda pode haver ambiguidade residual "mais difícil" (visual) em alguns casos, mas eu não gostaria de trocar isso pelo que agora parece ser uma enorme vitória de legibilidade quantitativa (como em: "linhas de código-fonte que exigem menos tokenização/esforço visual versus linhas de código-fonte que se tornaram mais ambíguas" ).

Desse ângulo crate - intern (ou qualquer outra assimetria) também pareceria um passo atrás.

Dito isto, não sei sobre a análise de ambiguidade. Se eu tivesse que escolher um, eu preferiria ter uma boa história em torno de " crate significa coisas de caixote" do que uma boa história em torno de " crate ::foo::bar apenas funciona".

Meus dois centavos são que:

  • Eu tenho usado crate mod , crate struct , crate fn , ... extensivamente e acho extremamente útil.
  • Eu realmente não me importo com o nome ( crate , pub(crate) , ...), desde que não seja muito longo porque eu o uso com frequência.

Se dependesse de mim, eu usaria vis como palavra-chave e o tipo de visibilidade como modificador, por exemplo, vis(pub) , vis(crate) , etc. sentido para mim.

Dado que já estamos presos com pub como um "especificador de visibilidade", eu realmente gosto crate . O pub(crate) lê para mim como público para este módulo, privado para a caixa - acho estranho usar público e privado ao mesmo tempo aqui.

Introduzir novas palavras-chave e palavras-chave contextuais, etc., na minha opinião, não vale a pena. Ensinar que existem duas modificações de visibilidade pub e crate , e que uma significa pública e a outra significa privada para a caixa, meio que faz sentido para mim, mas talvez eu tenha me acostumado a crate já nas últimas duas semanas.

Para aqueles que sugerem uma palavra-chave já usada (por exemplo: crate ) confunde significados, eu diria que o contexto é mais importante do que a palavra em si. O cérebro analisa tudo com contexto (como o compilador analisa isso é uma questão diferente): isso explica por que não combinamos o significado semântico de for em for x in y e impl X for Y .

Da mesma forma, a introdução de crate como um qualificador de visibilidade provavelmente não criaria confusão porque seu significado, no contexto de um qualificador de membro ou função, é óbvio quando fornecido com esse contexto adicional. Por exemplo, crate fn my_func(); não é lido como "este é um engradado", ele lê como "esta é uma função visível ao engradado".

Dito isto, o fato de ser um substantivo é inconsistente. Eu seria a favor da criação de uma nova palavra-chave do qualificador de visibilidade para resolver esse problema.

Na verdade, se há algo que definitivamente vai confundir os usuários, é a sintaxe pub(crate) que intuitivamente se parece com uma chamada de função e não tem outro equivalente sintático em nenhum outro lugar da linguagem. Para mim, parece um hack feio.

Como alguém que levantou preocupações sobre o uso de crate como substituto de pub(crate) e depois de ler o post mais recente de @aturon :

Caixa de suporte como um modificador de visibilidade (rastreado aqui 138. Dados os comentários até agora, é improvável que esse recurso seja estabilizado para Rust 2018 .

Eu só quero ter certeza de que sou totalmente a favor de substituir pub(crate) por algo (como acho que a maioria é).

Em ordem de preferência, com o que acho mais fácil de entender, especialmente para quem é novo ou não familiarizado com Rust:

  1. intern (ou alguma outra nova palavra-chave semelhante)
  2. crate
  3. pub(crate)

Se a equipe principal sentir que intern ou algo semelhante nunca seria aceito, então eu ficaria atrás crate , pois ainda acho que é uma grande melhoria em relação a pub(crate) , por as razões que o @Centril e outros articularam.

Então, eu não atrapalharia isso se a equipe principal, muito mais experiente, sentir que esse é o melhor caminho a seguir. É legal apenas ser capaz de fornecer feedback e expressar ideias para consideração. 👍 Ferrugem!

@ralfbiedert

Inicialmente, temi que pudesse haver ambiguidade (visual); mas para mim aconteceu o contrário: se eu vejo o caixote agora eu sei que é, bem, "coisas do caixote". Seja importando módulos ou declarando visibilidade. O que exatamente é na esmagadora maioria dos casos muito claro a partir do contexto (como a ambiguidade em inglês).

@zesterer

Para aqueles que sugerem que uma palavra-chave já usada (por exemplo: crate) confunde significados, eu diria que o contexto é mais importante do que a palavra em si. O cérebro analisa tudo com contexto (como o compilador analisa isso é uma questão diferente): isso explica por que não combinamos o significado semântico de for in for x in y e impl X for Y.

Não estou querendo chamar vocês dois pessoalmente, mas servir como exemplos das pessoas a favor da mudança depois de usá-la.

Embora eu ache estranho, minha maior preocupação é com os não-rustáceos.

  • Como isso pode afetar a opinião de alguém na avaliação da ferrugem? Uma coisa peculiar de sintaxe não deve ser suficiente para dissuadi-los, mas se você empilhar com vidas e qualquer outra coisa "estranha", pode desencorajar as pessoas
  • Como isso afeta as pessoas que estão aprendendo Rust?
  • Como isso afeta as pessoas que não conhecem o Rust, mas precisam modificá-lo?

Eu adoraria se pudéssemos fazer estudos de usabilidade sobre isso para saber melhor o impacto dessas preocupações.

@epage , concordo plenamente, as partes voltadas para o usuário do Rust devem ser testadas em UX. No entanto, acho que é isso que está acontecendo agora, e estamos discutindo os resultados.

Para adicionar a isso, algumas observações anedóticas de nossa empresa:

Eu sou o "advogado da ferrugem" em nosso departamento, trabalhando com 3 outras pessoas. Todos têm uma sólida experiência em C#, mas são relativamente novos no Rust. Outro dia migrei nosso projeto de pesquisa para Rust 2018, junto com o " crate -stuff".

Quando analisamos o código, as conversas foram aproximadamente assim:

"Então, aqui estão algumas outras mudanças que fiz; novo sistema de importação; modificadores."

"O que isso faz?" (apontando para use crate::object e crate x: object )

"Importar desta caixa." e "Modificador de visibilidade".

"Ah, ok. Mais alguma coisa que mudou?"

Fim de discussão.

Certamente, conversamos um pouco mais sobre novos recursos e se devemos adotar determinados padrões; mas o "aspecto de ensino" desses dois itens se resumia a poucas palavras e não foi mencionado desde então (que eu saiba).

Se eu ouvir mais alguma coisa na próxima vez que conversarmos, atualizarei este comentário.

@ralfbiedert Obrigado por compartilhar isso!

@epage , concordo plenamente, as partes voltadas para o usuário do Rust devem ser testadas em UX. No entanto, acho que é isso que está acontecendo agora, e estamos discutindo os resultados.

Embora eu valorize essas histórias de UX, especialmente pelo lado da capacidade de aprendizado, não acho que qualificaria o processo desse problema como teste de UX. Meu comentário está se referindo a um processo mais formal que pode ajudar a obter uma compreensão mais profunda, eliminar preconceitos etc.

Aqui estão alguns pensamentos vindos de um novato em Rust. Em primeiro lugar, quero dizer que algo que realmente parece sensato e agradável com essa linguagem é a abordagem "imutável por padrão, privada por padrão".

Agora, pub é legal porque é simples e esperado em linguagens modernas. Eu sinto que ter que desaprender isso no contexto do Rust e espalhar outra palavra-chave em todos os lugares é um pouco desajeitado. Semanticamente, parece certo significar "este é um botão que aparece na caixa", a caixa sendo o módulo: visibilidade "de um nível para cima".

Então, para mim, usar crate ou outra palavra-chave dessa natureza em vez de pub dá uma coceira: se ser público é o padrão, ser exportado para fora da caixa deve ser ainda mais especial . Ou seja, a API do engradado deve ser indicada de forma especial.

Então, eu concordo plenamente com @epage , pub deve permanecer o mesmo e um pub(extern) de algum tipo ser introduzido. Palavras-chave entre parênteses realmente parecem cabeludas, então talvez mereça uma palavra-chave dedicada. A palavra-chave crate funcionaria nesse sentido, posso vê-la significando "este é um membro da caixa exportado". Ou export na verdade, não sei. Talvez todo o meu ponto seja perdido, e tudo isso equivale a "as palavras-chave não estão corretas". Mas pub é tão comum que não parece especial, então não deve representar algo realmente especial (a API exportada para caixas).

Eu assisti a uma palestra na RustConf neste fim de semana que usou muito pub(crate) em seus exemplos de código, e isso realmente me fez desejar o velho crate . Eu ainda sou muito pró o plano original.

@steveklabnik

Eu assisti a uma palestra na RustConf neste fim de semana que usou muito pub(crate) em seus exemplos de código, e isso realmente me fez desejar uma caixa simples e velha. Eu ainda sou muito pró o plano original.

O contexto deste comentário é principalmente da RustConf ou leva em consideração esse tópico e pressupõe um desacordo com ele? Anteriormente, forneci uma solução alternativa, não para pub(crate) mas para os requisitos que conduzem a qualquer uma das alterações de pub e espero que satisfaça as necessidades das pessoas.

Ver

@superseed

Então, eu concordo plenamente com @epage , o pub deve permanecer o mesmo e um pub (externo) de algum tipo ser introduzido. Palavras-chave entre parênteses realmente parecem cabeludas, então talvez mereça uma palavra-chave dedicada. A palavra-chave crate funcionaria nesse sentido, posso vê-la significando "este é um membro da caixa exportado". Ou exportar na verdade, não sei. Talvez todo o meu ponto seja perdido, e tudo isso equivale a "as palavras-chave não estão corretas". Mas pub é tão comum que não parece especial, então não deve representar algo realmente especial (a API exportada para caixas).

RE "As palavras-chave entre parênteses realmente parecem cabeludas"

Embora pessoalmente eu tenha pensado que eles eram legais quando os descobri (muito melhor do que tudo ou nada friend ), minha maior preocupação é não criar uma sintaxe paralela, mas abraçar o que temos ou encontrar uma solução alternativa.

Por outro lado...

RE Ou export na verdade,

Eu não acho que adicionar um export contradiz meu comentário anterior em contraste com crate . Nesse contexto, export pode ser tratado como diferente de visibilidade. export implicaria pub(crate) . Eu suspeito que isso não terá muito problema no ensino.

Eu posso ir de qualquer maneira nesta extensão da minha ideia original.

@superseed

pub […] visibilidade "de um nível para cima".
A palavra-chave crate funcionaria nesse sentido, posso vê-la significando "este é um membro da caixa exportado".

Acho que sua compreensão do significado dessas duas palavras-chave pode ser exatamente o oposto do que é proposto aqui, que é que pub significa público para todos enquanto crate significa acessível a partir da mesma caixa.

@epage

No caso de pub(crate) , ele oferece um recurso muito legal e lê bem, mas parece muito com uma chamada de função aos meus olhos. ou seja, sem realce sintático eu provavelmente ficaria muito confuso, e realce não deveria ser necessário para entender a semântica de uma linguagem.

@SimonSapin

De fato, e eu percebo que é assim que deve ser entendido, mas crate -- sendo um substantivo -- parece que está declarando um engradado (?) ou uma propriedade do engradado. Ênfase declarando e não qualificando.

E public / pub é um qualificador tão onipresente que não parece (para mim!) que deveria significar "isso é exportado para fora da caixa". Tem o significado de "isso é visível fora do contexto em que estou", como é o caso de seu uso na qualificação da visibilidade do membro struct (e me corrija se estiver errado, mas não acho que a semântica está mudando nesse caso).

E public/pub é um qualificador tão onipresente que não parece (para mim!) que deveria significar "isso é exportado para fora da caixa". Ele tem esse significado de "isso é visível apenas fora do contexto em que estou", como é o caso de seu uso na qualificação da visibilidade do membro da estrutura (e me corrija se estiver errado, mas não acho que a semântica seja mudando nesse caso).

pub sempre significou "isso é exportado para fora da caixa" - isso não é uma mudança, é como já é. O fato de que muitos assumem o contrário é o motivo pelo qual o nível de visibilidade pub(crate) está sendo empurrado.

pub sempre quis dizer "isso é exportado para fora da caixa"

Acho que esse entendimento também pode causar alguma confusão, porque não é o quadro completo. pub realmente significa "Eu não me importo quem fora deste módulo acessa este item/campo/método". Para ser exportado do engradado, ele ainda requer que um caminho para o item também tenha os mesmos modificadores pub neles.

Esse detalhe é bastante comum em muitos idiomas. É também por isso que não estou interessado no fiapo unreachable_pub , já que isso é parte do que está pressionando tanto esse problema. Se eu tenho um tipo que nunca é exportado no nível superior, então me incomodar que marquei seus métodos pub parece barulho.

@rpjohnst É realmente o que sempre significou? Não foi a cadeia de "visible from super " do topo do engradado que fez um elemento exportado, e não qualificando o próprio elemento folha como pub ?

Não, essa não é toda a história, e o esclarecimento de @seanmonstar sugere o resto. A maior exceção é a reexportação - você pode pub use algo cujos módulos pai sejam privados. Um exemplo mais estranho é algo assim , onde você tem permissão para usar um item pub em uma interface pública mesmo se seus módulos pai forem privados.

E indo na outra direção, pub(crate) e visibilidades menores não podem ser ignoradas da mesma maneira - você não pode pub use algo que já não seja pub , mesmo que o pub use não é visível de fora da caixa.

Portanto, a própria visibilidade de um item não é diretamente sobre sua visibilidade para super , mas seu "limite superior" de visibilidade em qualquer lugar .

Opa, obrigado pelo esclarecimento! Eu tinha um modelo muito mais ingênuo em mente. Faz mais sentido em relação aos comentários anteriores sobre "o significado atual de pub".

Discutimos brevemente hoje na reunião @rust-lang/lang:

  • Muitos de nós se sentem positivos sobre isso, mas há dúvidas persistentes sobre a escolha da palavra-chave e se ela pode criar confusão quando combinada com crate::foo::bar caminhos
  • No entanto, vale ressaltar que temos que decidir que tipo de maneira de resolver struct Foo ( crate :: foo :: Bar ) -- este é um campo privado do tipo (crate::foo::Bar) ou é um campo crate do tipo ::foo::Bar ?

    • Sinceramente, não tenho certeza do que analisamos como hoje

Resposta: nós o analisamos como um caminho ( playground ).

Isso parece .. provavelmente ok para mim, porque acho que os caminhos ::foo::bar se tornarão cada vez mais raros.

Muitos de nós se sentem positivos sobre isso, mas há dúvidas persistentes sobre a escolha da palavra-chave e se ela pode criar confusão quando combinada com os caminhos crate::foo::bar

@nikomatsakis há notas de reunião ou um resumo para nos atualizarmos? Dentro deste tópico, não vi discutido pelo menos uma das minhas preocupações[0] nem muita discussão sobre as contrapropostas. Talvez [0] e alguns dos outros tenham sido discutidos nos vários tópicos internos, mas isso é muito para investigar.

[0] criando uma sintaxe de visibilidade paralela empurrando pub(...) para a obscuridade com a sensação de que devemos remover ou abraçar pub(...)

@epage

@nikomatsakis há notas de reunião ou um resumo para nos atualizarmos?

Não desculpe; Nós não discutimos isso por muito tempo (alguns minutos no máximo) e não escrevemos nenhuma nota de reunião sobre isso.

@eddyb aludiu brevemente a my como um modificador de visibilidade mais curto e ergonômico.

Acho que disse mine mas my é ainda mais curto, lindo!
(Para constar, eu estava meio brincando na reunião)

EDIT : se my for local de caixa, podemos substituir pub por our ? por exemplo:

our struct Foo(my FooImpl);

(Para constar, eu estava meio brincando na reunião)
se my for local da caixa, podemos substituir pub por our ?

Perl: transformando piadas em realidade.
https://perldoc.perl.org/functions/my.html
https://perldoc.perl.org/functions/our.html

my é legal (e já apareceu antes), o fato é que não é mais claro do que local , internal , ou o que quer que seja, em relação ao que (ou em seu caso, cujo ), que é todo o problema.

A situação embaraçosa em que estamos é que queremos ter três níveis de privacidade - "completamente público", "completamente privado" e "algum lugar no meio" (ou seja, nível de caixa) - e devido a restrições de compatibilidade com versões anteriores, estamos presos com o primeiro deles sendo necessariamente pub , o segundo sendo o padrão implícito e tendo que criar algo novo para o terceiro. E o inglês não tem muitas palavras que denotam "nem completamente global, nem completamente local, mas em algum lugar no meio" com precisão.

E a palavra-chave crate é a que satisfaz isso, porque diz bem no nome qual é o escopo real -- é o engradado. Mas (antes de você quebrar os "eu sabia !"), o preço disso é que não é mais evidente que é um modificador de visibilidade . "Pub" é a abreviação de "público", isso, pode-se intuir. Mas nenhuma outra linguagem tem o conceito de "caixa" (com esse nome); para ter alguma esperança de entender crate struct , é preciso primeiro aprender sobre isso. 1 Isso exige que façamos uma retirada adicional do "orçamento da estranheza da linguagem", e as opiniões podem diferir sobre se o saldo ainda é positivo.

Enquanto isso pub(crate) resolve os dois problemas -- diz que é um modificador de visibilidade, e diz qual é o escopo -- mas em troca é longo e estranho.

Então essa é basicamente a forma da situação.

1 (Alguém acima descreveu uma interação que foi, "eles perguntaram o que crate significava, eu disse a eles que é um modificador de visibilidade, e isso foi tudo". A situação problemática, e possivelmente mais comum, é quando você não tem um rustáceo sentado ao seu lado.)

FWIW, eu ficaria totalmente bem com our ou my para itens locais da caixa.
our é mesmo uma palavra-chave de três letras e se alinha bem com pub ~e com Perl~.
O problema é que eles soam muito informais (para falantes nativos de inglês?)?

Como as pessoas se sentem sobre intern ? É um caractere maior que crate , mas fora isso acho que será mais intuitivo do que crate para pessoas novas no Rust e tem uma boa simetria para a palavra-chave extern .

IMO our e my têm a mesma fraqueza que local e internal : eles não são muito claros sobre seu escopo. local em particular é bastante confuso, já que o escopo seria radicalmente diferente das variáveis ​​locais onde local significa privado para o escopo delimitador, que para um item seria o módulo, não o engradado. Acho internal um pouco inespecífico. Interno para quê? O módulo? O tipo? A caixa? Pode ser óbvio para aqueles que vêm de línguas onde é usado, mas não será necessariamente para outros. our e my são ainda mais vagos. Em contraste crate é muito claro sobre o escopo.

Em relação pub(extern) , eu realmente tenho uma pergunta. Faz algum sentido ter extern "C" fn foo() {} , sem o pub na frente? Porque se não, poderíamos reutilizar extern fn foo() {} para nossas funções regulares, não "C" abi Rust também. Eu estava pensando que poderíamos unificar isso e não manter a sintaxe externa especial para FFIs. Isso significaria que extern agora desuga para pub(extern) , pub permanece o mesmo de hoje, mas aceita uma string ABI opcional quando o item a suporta e um fiapo para pub itens sendo exportados sem pub(extern) ou extern .

extern fn foo() {
    println!("Just called a Rust function from Rust!");
}

#[no_mangle]
extern "C" fn foo_from_c() {
    println!("Just called a Rust function from C!");
}

Eu não vi isso mencionado nos tópicos que li, então peço desculpas se isso já foi discutido antes!

Faz algum sentido ter extern "C" fn foo() {} , sem o bar na frente?

Sim, às vezes você só quer usar foo como um ponteiro de função, por exemplo. E, de fato, a sintaxe extern fn foo() {} não pode ser reutilizada para isso, porque extern sem "C" é o padrão da C ABI, e isso é considerado idiomático pelo menos por alguns.

Aqui está uma sugestão que surgiu há muito tempo - talvez possamos dar outra chance agora que alguns aspectos do novo sistema de módulos foram cristalizados?

// Public to the world.
pub struct Foo;

// Private to the crate.
priv struct Foo;

// Basically not visible at all (only inside the module).
struct Foo;

Acredito que isso faz sentido se pensarmos em:

  • "público" como "público para o mundo"
  • "privado" como "privado da caixa"
  • "sem modificador de visibilidade" como "basicamente não visível"

Algumas pessoas tiveram uma reação instintiva por priv não ser a mais restritiva, mas quero fazer dois pontos sobre isso:

  1. No Rust, os módulos são usados ​​para organizar as coisas em namespaces, enquanto as grades são usadas para definir interfaces. Portanto, se uma caixa é uma "unidade de API", faz sentido que os modificadores de visibilidade falem principalmente sobre caixas.

  2. Eu acho que Java cometeu um erro de private significando "privado para a classe" e nenhum modificador de visibilidade significando "visível dentro do pacote". Para mim, faz mais sentido que nenhum modificador (ou seja, o padrão) seja o mais restritivo.

@stjepang Eu diria que, na maioria das outras circunstâncias, "privado" terá uma conotação mais restritiva do que um estado não modificado. O espectro privado-padrão-público em um sentido geral é análogo ao protegido-disponível-anunciado.

Um clube privado é mais exclusivo do que um clube.
Um ato privado implica que algum esforço foi feito para se esconder da visão geral.
Um pensamento privado deveria ser um conceito redundante, dado o fracasso da evolução em nos dotar de telepatia, mas a maioria das pessoas reconhece que significa um pensamento destinado a não ser compartilhado.

Como um aprendiz de idiomas inexperiente, também sugiro que uma palavra-chave adicional seja um fardo cognitivo menor do que uma única palavra-chave com vários significados dependentes do contexto. Veja Costello, L e Abbot, B "Who's on first", 1938.

Sinto que my e our teriam conotações que não queremos, deixando de lado a dificuldade de reservá-las como palavras-chave. Eles são uma piada divertida, mas não acho que devemos seguir esse caminho.

Sinceramente, sinto que as pessoas aprenderiam o que significa visibilidade crate . Acho que o maior problema vem do código que se torna difícil de ler ou ambíguo para analisar:

crate struct S(crate crate::Foo);

crate struct S(crate ::Foo);

Eu pessoalmente não vejo isso como um impedimento, mas eles são definitivamente preocupações legítimas aqui.

Há um paralelo de pub(path) na linguagem Scala, que é private[path] , que funciona praticamente da mesma forma. Ele lê um pouco diferente, dizendo "este item é privado, permitindo apenas que as pessoas dentro de $path o visualizem". Mas tornar algo privado no Scala requer uma anotação, pois o padrão é público, o que não é o caso do Rust.

Ocorre-me que o conceito C++ de friend s também é semelhante a pub(path) , como outro ponto de precedente.

Em última análise, os problemas são:

  1. a palavra-chave crate é usada para importações de caminhos relativos e como modificador de visibilidade,
  2. a palavra-chave crate impede uma sintaxe de modificador de visibilidade unificada como pub(...) ,
  3. alguns não gostam da sintaxe pub(crate) (muito longa, parece uma chamada de função).

Após 5 minutos de reflexão profunda, cheguei ao seguinte... :P

Sintaxe especial para os modificadores de visibilidade

_(usando @ como exemplo)_

<strong i="18">@pub</strong> use crate::Foo;

<strong i="19">@crate</strong> struct Bar;

Pessoalmente, acho isso muito feio e não gostaria de digitar @crate ou pub(crate) .

Palavras-chave de modificadores de visibilidade distinta

Como já existe o pub e extern , acho que a palavra-chave crate se encaixa muito bem (o que não surpreende quando vem de idiomas com os usuais public , protected , private palavras-chave).

crate struct Foo;

crate fn path() -> PathBuf { ... }

Mas como eu disse, isso não funciona bem com o prefixo de importação crate e estou começando a sentir que temos isso ao contrário. Eu sinto que o verdadeiro problema está nas mudanças de clareza do caminho, por exemplo, sem realce de sintaxe:

use crate::utils;

parece que crate não tem nenhum significado especial.

Com grande inspiração da sintaxe de macros declarativas, em vez de encontrar algum tipo de sintaxe unificada para modificadores de visibilidade, prefiro ter o seguinte:

use std::io;
use std::path::Path;

use log::info;

use $crate::utils;

crate fn hello() -> io::Result<()> {
    utils::rm_rf(Path::new("/"))?;
    info!("Goodbye, World!");
}

( self , super e crate âncoras especiais para importações de caminhos precisariam de um prefixo, por exemplo, $crate , o que deixa bem claro que são especiais e parecem variáveis)

Exemplo complicado:

crate struct Foo(crate crate::Bar);

torna-se:

crate struct Foo(crate $crate::Bar);

Parece que há um problema de rastreamento duplicado: https://github.com/rust-lang/rust/issues/45388.
Fechando aquele a favor deste.

Existe uma razão pela qual a implementação do rustc está fazendo dogfood desse recurso? Cada instância de crate fn pode ser alterada para pub(crate) fn e parar de depender de um recurso instável AFAICT.

Não vejo uma boa razão para fazermos isso. Tanto o Clippy quanto o rustc usam recursos instáveis ​​o tempo todo e deveriam, porque nos permite testá-los mais extensivamente, tanto em termos de captura de bugs na implementação, quanto porque podemos ter uma ideia de como é usá-los.

Nesse caso, o uso de crate como um modificador de visibilidade no Clippy e no rustc está, na minha opinião, mostrando que ele lê melhor que pub(crate) e que a maioria dos problemas referenciados neste problema de rastreamento não são -questões na prática. Acho que https://github.com/rust-lang/rust/issues/53120#issuecomment -413466129, https://github.com/rust-lang/rust/issues/53120#issuecomment -414392549 e https:// /github.com/rust-lang/rust/issues/53120#issuecomment -413498376 também sugere que crate como um modificador de visibilidade funciona bem fora também.

Como funciona bem na prática, já que muitos de nós na equipe de linguagem se sentem positivos sobre isso , e porque foi aceito pela RFC , acho que devemos considerar estabilizar crate como um modificador de visibilidade depois de considerar como devemos analisar struct Foo ( crate :: foo :: Bar ) ( atualmente como um caminho, e provavelmente está certo ).

FWIW, eu uso esse recurso no cargo-n64 e tem sido muito bom!

Eu uso crate em rustc o tempo todo porque é curto e não tem parênteses como pub(crate) .
Eu ainda não gosto de como ele lê embora.
Ele também não tem 3 letras, então a formatação muda junto com pub <-> crate muda.
Eu ainda gosto de our sem ironia.

@petrochenkov Meu entendimento do que você escreveu é que você prefere crate a pub(crate) , mas também gostaria de algo melhor que crate . Essa é uma avaliação precisa?

FWIW, eu ainda acho que intern é uma boa opção.

  • Sem parênteses
  • Menor que pub(crate) (embora um caractere maior que crate )
  • Lê melhor (IMO) do que crate (que é usado para outras coisas como caminhos, por exemplo crate::foo::bar )
  • Tem boa simetria com extern existente
  • Familiar, pois outras linguagens usam algo semelhante ( internal ). Kotlin, C#, etc.

Dito isto, também concordo que pub(crate) deve ser substituído por algo .

bem, está resolvido então-- três letras são legais, e "estagiário" é legal, então... int . ;)

Podemos ter um fiapo para o caso crate ::T (com um espaço)?

@Centril Alguns de nós estávamos apenas discutindo o caminho a seguir no #rocket. Com base em seu comentário recente, existe a possibilidade de um FCP proposto em um futuro próximo?

@jhpratt Eu queria escrever um artigo e eventualmente propor, mas estou ocupado com outras coisas. Vou tentar encontrar algum tempo no futuro próximo.

Então, eu estava apenas navegando em problemas, procurando algo sobre macros, e encontrei este.

Agora que temos pub(crate) em stable já há muito tempo, eu me pergunto, esse assunto não deveria ser encerrado?

Curiosamente, isso surgiu em uma recente reunião da equipe lang , onde discutimos isso como um possível problema que gostaríamos de reviver.

Falando pessoalmente, eu definitivamente sinto falta de poder escrever crate fn e crate foo: T em campos e esse tipo de coisa. Não é uma grande diferença sintática de pub(crate) mas acho que torna o código muito mais legível, principalmente em estruturas que têm muitos campos públicos. Também acho que contribui para um "modelo de privacidade" simplificado e útil -

  • structs, os campos são locais para um módulo (raciocínio muito estreito)
  • ou eles são usados ​​em algum lugar dentro da caixa atual ( crate , tem que fazer um ripgrep)
  • ou são públicos para o mundo ( pub )

Na minha opinião, há alguma interseção entre essa palavra-chave e as alterações previstas em https://github.com/rust-lang/rust/issues/48054 , e eu prefiro garantir que as adotemos juntas. Esqueço os detalhes, mas lembro que havia erros que se cometeriam ao tentar colocar em prática o modelo acima.

Acho que o primeiro passo para isso seria alguém tentar fazer uma redação documentando a história e ter certeza de que destacamos todas as preocupações que foram levantadas.

Uma preocupação específica que me lembro é a ambiguidade sintática de

struct Foo(crate ::x)

Hoje, isso é aceito e crate ::x analisa como o caminho crate::x , mas plausivelmente o usuário queria que crate servisse como um modificador de visibilidade com ::x como um caminho .

Eu estaria inclinado a reintroduzir o modificador crate e manter a análise do caso acima exatamente como é hoje. Desde Rust 2018, os caminhos ::foo foram amplamente obsoletos - eles ainda existem e podem ser úteis em determinados contextos específicos, como macros, mas a maior parte do termo agora incentivamos caminhos absolutos que se parecem com crate_name::b , onde crate_name pode ser a palavra-chave crate ou o nome de alguma outra caixa. Portanto, é bastante provável que crate::x (ignorando os espaços em branco) na verdade fosse um caminho e, portanto, a análise atual esteja correta.

Se quisermos resolver a possível confusão do usuário, acho que um lint sensível a espaços em branco é uma ideia razoavelmente boa. Em outras palavras, struct Foo(crate ::x) avisaria, mas struct Foo(crate::x) não, embora ambos sejam aceitos e equivalentes.

Pessoalmente, prefiro a sintaxe unificada e o analisador simples lookahead(1); Além disso, uma caixa é uma caixa, e há crates.io por aí, e todas essas coisas não têm nada a ver com visibilidade _diretamente_ — apenas no contexto de pub(_) .

Mas bem, o que eu sei? É apenas mais um ponto de vista. Vocês, sem dúvida, têm mais experiência e opinião mais valiosa.

@nikomatsakis Curioso se você pensou em intern para este caso de uso (ou está reservando uma nova palavra-chave fora do escopo neste momento?).

Depois de alguns anos, meu sentimento ainda é o mesmo: otimizar para legibilidade . Acho que leio código muito mais do que escrevo . E assim, minha opinião é que é mais claro para mim ler pub(scope) , que pode ser pub , pub(crate) , pub(super) , pub(in proto::h1) .


No entanto, acho que não estamos realmente adicionando nada de novo à conversa com essas opiniões, tenho certeza de que já dissemos tudo em comentários anteriores. A decisão deve ser baseada em algo novo? Ou dito de outra forma, como decidimos que agora a decisão de adotar essa sintaxe deve ser sim quando era não ou adiar alguns anos atrás?

Também acho que contribui para um "modelo de privacidade" simplificado e útil -

  • structs, os campos são locais para um módulo (raciocínio muito estreito)
  • ou eles são usados ​​em algum lugar dentro da caixa atual ( crate , tem que fazer um ripgrep)
  • ou são públicos para o mundo ( pub )

Não consigo entender o benefício dessa simplificação e como vale a pena a perda de poder expressivo. Para o que vale a pena, muitas vezes deixo os itens públicos para seus módulos pai (para que os módulos irmãos possam usá-los), mas não para a caixa inteira. Público para o módulo de avós menos, mas ainda ocasionalmente.

Eu sinto que depreciar pub(super) seria uma perda significativa.


Separadamente, não estou entusiasmado em usar o substantivo crate como um qualificador que modifica um item que pode existir independentemente. Para comparação: pub(lic), unsafe e const(ant) são adjetivos. Os substantivos já usados ​​como palavras-chave nas definições de itens não são qualificadores, mas indicam a natureza desse item: função, traço, módulo, …

As caixas já são um conceito que tratamos, mas nesta proposta uma definição de item que começa com crate não define uma nova caixa.

Uma pequena nova informação:

rust-analyzer fornece conclusões e ajuda para adicionar pub(crate) , o que (subjetivamente) torna muito menos chato digitar, com três pressionamentos de tecla.

Concordo que pouca informação nova está sendo adicionada aqui. Acho que um bom próximo passo, se quisermos defender a proposta, seria voltar atrás, resumir as preocupações pendentes e trazê-las à equipe lang para tentar chegar a uma decisão final. Eu certamente preferiria aceitar ou rejeitar esta proposta, estou cansado de tê-la no limbo.

Analisando rapidamente toda esta edição, acho que o comentário recente de @nikomatsakis resume as coisas muito bem. Além de algumas pessoas selecionadas que ainda suportam coisas como intern , crate parece ser o mais lógico (e foi aceito na RFC 2126 ). A única questão realmente pendente é como analisar fn foo(crate ::bar) .

Um lint sensível a espaços em branco de aviso por padrão parece o lugar mais lógico para começar. crate ::bar é atualmente analisado como um caminho e teria que permanecer assim em Rust 2015 e 2018. No entanto, imaginei que seria um candidato a uma mudança importante em uma edição.

O caso crate ::bar é totalmente sem importância na prática e já se comporta de forma consistente com o resto da linguagem. Tem sido consistentemente o arenque vermelho da discussão, por favor, não concentre a atenção nisso.

Eu certamente preferiria aceitar ou rejeitar esta proposta, estou cansado de tê-la no limbo.

Acho que votaria pela rejeição.
Eu tenho usado consistentemente crate em vez de pub(crate) em rustc e, apesar de ser mais curto, ainda parece fora de lugar na maioria das vezes, especialmente em campos ou importações, e escolhendo entre crate e pub(crate) parece escolher entre dois males sem ter certeza de qual é o menor.

Sim. O que é mais importante, é o que @SimonSapin mencionou que crate bar de fato não define uma nova caixa, apesar de parecer que sim.

@petrochenkov Você não acha que um fiapo faz sentido? Pessoalmente, se eu visse crate ::bar sem ver essa discussão, esperaria que ela se comportasse como pub(crate) ::bar . Acho que permitir espaços em branco nos caminhos _de todo_ é confuso.

@jhpratt Seria difícil negar espaços em branco entre segmentos de caminho, devido à natureza de como os analisadores funcionam com tokens. Também quebraria uma quantidade insana de ferramentas como quote!, syn e muitas outras.

Eu acho que eu apoiaria fechar isso também. Já vi tanta confusão expressa sobre o significado dessa construção que não acho que o ganho de brevidade valha a perda potencial de legibilidade.

Isso pode se encaixar melhor no problema de rastreamento "maior" (mas fechado) nº 44660, mas também está diretamente relacionado aos modificadores de visibilidade e não se encaixa nas outras subquestões do nº 44660:

Em algum momento eu me lembro de alguém sugerindo que pub(path) agora poderia ser legal, substituindo o formulário pub(in path) e subsumindo pub(crate) e pub(super) . Isso parece ser uma boa simplificação de pub(...) , embora em uma direção diferente de crate , que podemos considerar também.

Edit: Na verdade, não tenho certeza se isso funciona ... struct S(pub(path) Type) é ambíguo (para análise LL-esque) com coisas como struct S(pub (Type,)) .

Então, tenho pensado nisso nos últimos meses. Acho que cheguei à posição "fechada". Acho que o resumo da minha posição é o seguinte:

  • A ideia de "três níveis de visibilidade" (módulo, caixa, mundo) é relativamente simples, o que é atraente, mas deixa escapar casos comuns do mundo real. pub(super) , em particular, acho bastante comum na prática, embora seja raro exigir mais de um nível (ou seja, pub(crate::foo) ). Por exemplo, muitas vezes eu quero ter módulos que tenham submódulos, e usar a visibilidade da caixa para esses detalhes não comunica o nível de privacidade pretendido.
  • O modelo de "local para alguma parte da caixa, ou público para o mundo" também é conceitualmente simples e elegante, e abrange todos esses casos de uso.
  • pub(crate) fn , embora significativamente menos conciso do que apenas crate fn , não é tão ruim. É fofo que pub(crate) se estenda para pub(crate::foo) , que cobre o outro caso de uso que às vezes recebo (ou seja, módulos "grandes" dentro de uma caixa), mas isso é tão detalhado que suspeito que raramente ou nunca ser usado, e muito provavelmente esses grandes módulos seriam melhor fatorados em subcaixas de qualquer maneira ...
  • Eu acho que os maiores obstáculos ergonômicos em torno de "níveis mistos de privacidade" vieram de fiapos e erros relacionados a nós tentando garantir que (por exemplo) todos os tipos que aparecem em um pub(x) fn fossem de privacidade adequada. Nós ajustamos essas regras e eu sinto que não tenho mais esses aborrecimentos - e se mais desses aborrecimentos surgirem, acho que podemos resolvê-los também.

    • Por exemplo, é possível escrever pub em campos para significar "tão público quanto a própria estrutura", e acho que funciona muito bem.

E, claro, o fato de não adicionar crate fn agora não significa que não podemos adicionar mais tarde. Em particular, acho que o modelo de "três níveis de privacidade" funcionaria melhor se tivéssemos alguma maneira de fazer "caixas leves e em linha" dentro de outra caixa. isto é, se em vez de ter um submódulo dentro do engradado, eu pudesse declarar um engradado privado com tudo o que isso implica (mais notavelmente, provavelmente, um relacionamento do tipo DAG com outras coisas). Não tenho certeza se os engradados leves e embutidos realmente funcionariam, mas eles podem cobrir e substituir muitos dos casos de uso semelhantes a pub(super) . Se alguma vez explorar isso, consideraria reabrir a discussão em torno crate fn , pois pode se tornar significativamente mais útil/comum.

Em suma, eu seria a favor de remover o nível de visibilidade crate do compilador e remover o portão de recursos.

Eu só queria verificar quando esse recurso pode ser estabilizado e estou surpreso e desapontado com os planos de removê-lo. Eu tenho usado isso no dia-a-dia desde que foi adicionado pouco tempo depois e quase não me incomodo com nenhum dos problemas discutidos acima. Ainda não escrevi nada parecido com crate ::path , por exemplo, e provavelmente nunca escreverei, pois nunca toquei na sintaxe ::path .

Há espaço para melhorias, com certeza. A palavra-chave poderia ser melhor escolhida, pub(super) ainda é inconveniente e é um incômodo receber avisos de código morto em todos os lugares quando uso visibilidade em nível de caixa para métodos auxiliares. Como usuário, no entanto, eu preferiria que esse recurso fosse deixado de lado (feature-gated) até que uma solução melhor fosse encontrada. A sintaxe pub(crate) é um tanto desagradável e desencoraja um pouco a divisão de módulos grandes em módulos menores e mais compactos.

acho que os maiores obstáculos ergonômicos em torno de "níveis mistos de privacidade" vieram de fiapos e erros relacionados a nós tentando garantir que (por exemplo) todos os tipos que apareciam em um pub(x) fn fossem de privacidade adequada.

Isso significa que também não habilitamos o lint "publicação inacessível" ( mod private { pub fn f() {} } )?

Heh, eu tenho pensado duas vezes enquanto leio vários códigos rustc e vejo crate em uso, e imagino que esses casos eram todos pub(crate) ... provavelmente valeria a pena fazer a transição experimentalmente apenas para ver como o diff me faz sentir. Lembro-me de me sentir triste por causa do giz quando o mudamos de noturno para estábulo, embora acho que agora que estou acostumado com isso não me incomodou tanto.

@matklad Espero que não, acho que o fiapo também é bastante importante. Para ser honesto, não sei ao certo por que não encontrei nenhum tipo de erro e aborrecimento do tipo que costumava ter. Talvez eu não tenha escrito bastante código Rust ultimamente! Eu definitivamente me lembro que eu costumava ter esses ciclos irritantes onde parecia que eu não poderia satisfazer o compilador exceto fazendo muito mais coisas pub do que eu queria.

Que tal manter pub(crate) e também adicionar um alias pubc ? Isso é bastante semelhante, não quebra nenhum código atual e remove a necessidade de digitar parênteses (o que o torna um pouco mais rápido).
Isso também permitiria pubs para visibilidade no pai.

Em suma, eu seria a favor de remover o nível de visibilidade crate do compilador e remover o portão de recursos.

Eu acho pub(crate) meio chato e barulhento quando estou lendo código. Seria muito bom ter o modificador de visibilidade crate .

E, claro, o fato de não adicionar crate fn agora não significa que não podemos adicionar mais tarde. Em particular, acho que o modelo de "três níveis de privacidade" funcionaria melhor se tivéssemos alguma maneira de fazer "caixas leves e em linha" dentro de outra caixa. ou seja, se em vez de ter um submódulo dentro do engradado, eu pudesse declarar um _crate_ privado com tudo o que isso implica (mais notavelmente, provavelmente, um relacionamento do tipo DAG com outras coisas). Não tenho certeza se os engradados leves e embutidos realmente funcionariam, mas eles podem cobrir e substituir muitos dos casos de uso semelhantes a pub(super) . Se alguma vez explorar isso, eu consideraria reabrir a discussão em torno crate fn , pois pode se tornar significativamente mais útil/comum.

Eu definitivamente gostaria dessas caixas "leves" que você mencionou! Seria muito melhor do que ir imediatamente para os espaços de trabalho, que são meio pesados.

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