A legibilidade é uma razão válida para não usar const nos parâmetros (referência)?

24

Ao escrever algumas funções, encontrei uma palavra-chave const em parâmetros como este:

void MyClass::myFunction(const MyObject& obj,const string& s1,const string& s2,const string& s3){
}

geralmente causa a divisão de uma linha em 2 linhas no IDE ou no vim, então eu quero remover todas as palavras-chave const nos parâmetros:

void MyClass::myFunction(MyObject& obj,string& s1,string& s2,string& s3){
} 

esse é um motivo válido para não usar const? É possível manter os objetos de parâmetro inalterados manualmente?

ggrr
fonte
110
"Ei, eu quero mudar funcionalmente meu programa" para torná-lo mais legível é um mau motivo.
Pieter B
37
O programa não está ficando mais legível de qualquer maneira - Depois de ver algo sendo entregue, constvocê tem uma forte dica de que não precisa se preocupar em como isso pode ser alterado na função.
tofro
43
Uma maneira melhor de melhorar a legibilidade é reduzir o número de argumentos.
Sep12
15
'const' sem dúvida melhora a legibilidade. Esta declaração deixa claro que obj não pode mudar!
Charles
14
O que ajudaria a legibilidade é adicionar um espaço após cada vírgula.
sam hocevar 23/09/16

Respostas:

182

A legibilidade é um motivo válido para aprender a usar o espaço em branco:

void MyClass::myFunction(
        const MyObject& obj,
        const string& s1,
        const string& s2,
        const string& s3
) {
    return;
}

Localizados ali, os parâmetros não serão confundidos com o corpo da função. Ao localizá-los em uma linha diferente, você não precisará reposicioná-los quando alterar o nome myFunctionpara algo mais descritivo. Não alterar a posição dos parâmetros quando eles não foram alterados é algo que os usuários da ferramenta de controle de origem apreciarão.

constsignifica alguma coisa. Não jogue fora só porque você está sem espaço e idéias. A legibilidade é rei, mas quebrar as coisas em seu nome é apenas desistir.

candied_orange
fonte
6
"você não precisará reposicioná-los quando alterar o nome de myFunction" - embora neste caso pareça que eles foram posicionados para se alinharem aproximadamente com a abertura (, e se for esse o caso, talvez seja necessário reposicionar se o comprimento do nome da classe + função for alterado em mais de 4 caracteres. Portanto, se você não precisar fazer isso, adicione um número fixo de níveis de recuo, não um número que dependa do tamanho do nome da função. Eu recomendaria um nível, esta resposta usa 6, mas qualquer número fixo alcança o objetivo declarado :-)
Steve Jessop
6
@CandiedOrange Estou surpreso que você não tenha usado o "formulário 6" nesta resposta ... é claramente menos feio!
Svidgen
6
Formulário 6 para a vitória. Um espaço de tabulação para um nível de recuo. Simples e eficaz. Problema resolvido :)
Lightness Races com Monica
2
Ok ok formulário 6 é. Essa é a variante mencionada por JeffGrigg em c2.
Candied_orange 22/09
4
@ random832 Acho que estamos firmemente no território do galpão de bicicletas agora. Aqui está a maneira correta de resolver isso: pesquise exemplos na sua base de código, consulte o guia de estilo da sua loja, pergunte aos desenvolvedores da sua loja e, se nada disso der uma resposta autorizada, use isso. Resolva as disputas que podem ir de qualquer maneira em um quarto. Uma vez que o trimestre tenha falado, seja consistente!
Candied_orange 22/09
52

Na verdade, a questão da legibilidade definitivamente vai na outra direção. Primeiro, você pode resolver trivialmente sua linha de execução usando o espaço em branco . Mas remover constnão apenas torna a linha mais curta, mas altera completamente o significado do programa.

Herb Sutter refere-se à constreferência constcomo a mais importanteconst porque uma referência a constpode se ligar a um temporário e prolongar sua vida útil. Uma referência lvalue para non- constcan, você precisa de uma variável separada.

void foo_const(std::string const& );
void foo_nc(std::string& );

std::string some_getter();

foo_const(some_getter());      // OK
foo_const("Hello there"); // OK

foo_nc(some_getter()); // error
foo_nc("Nope");   // error

std::string x = some_getter(); // have to do this
foo_nc(x);                     // ok
std::string msg = "Really??";  // and this
foo_nc(msg);                   // ok

O que isso significa para a usabilidade é que você precisará introduzir todas essas variáveis ​​temporárias apenas para poder chamar sua função. Isso não é ótimo para facilitar a leitura, pois essas variáveis ​​não têm sentido e existem apenas porque sua assinatura está errada.

Barry
fonte
6
O seu segundo parágrafo dá-me dores de cabeça tentando descobrir se constestá referindo-se constou para o outro consteo que consté realmente o mais importanteconst
Mindwin
3
@ Mindwin Eu acho que a ironia é que meu segundo parágrafo é claro e inequívoco, e eu não tenho idéia do que você está falando.
Barry
2
@ Barry É certamente inequívoco, mas levei algumas leituras desse parágrafo para tentar descobrir o que isso significava. Acho que alguns dos problemas são que ele pode ser analisado "Herb Sutter refere-se à const (em referência a const) como a const mais importante ..." ou "Herb Sutter refere-se a const in (referência a const) como a mais const importante ... "Acredito que este último seja o único agrupamento válido de palavras, mas é preciso um pouco para processá-lo. Talvez haja uma maneira de usar aspas para remover a ambiguidade?
Cort Ammon - Restabelece Monica
11
Eu acho que alguns compostos hifenizados esclareceriam isso.
precisa saber é o seguinte
2
ou especificamente utilizar const&em vez de referência a constcomo um substantivo (Frase) lá
Caleth
21

Resposta simples é "não".

A resposta longa é que a constpalavra-chave faz parte do contrato que a função oferece; informa que o argumento não será modificado. No momento em que você remove a constgarantia, sai pela janela. Lembre-se que você não pode razoavelmente manter o constness (ou qualquer outra propriedade) de algo usando documentação, convenções ou diretrizes - se o constness não é forçado pelo compilador, alguém vai pensar que eles podem fazer o seu trabalho mais fácil se eles mexer com o parâmetro "só um pouquinho". Considerar:

// parameter "foo" is not modified
void fna(Foo& foo);

void fnb(const Foo& foo);

Além do fato de que a última versão é mais concisa, ela também fornece um contrato mais forte e permite que o compilador o ajude a manter suas intenções. O primeiro não faz nada para impedir que a fna(Foo&)função modifique o parâmetro que você passa para ele.

Como na resposta @CandiedOrange, você pode usar espaços em branco para organizar o código e melhorar a legibilidade.

Mael
fonte
14

A remoção da constpalavra - chave remove a legibilidade porque constcomunica informações ao leitor e ao compilador.
Reduzir o comprimento horizontal do código é bom (ninguém gosta de rolar para o lado), mas há mais do constque texto. Você pode reescrevê-lo:

typedef string str;
typedef MyObject MObj;
void MyClass::myFunction(const MObj& o,const str& s1,const str& s2,const str& s3)

O que não altera o contrato, mas atende à necessidade de reduzir o comprimento da linha. Na verdade, eu consideraria o trecho acima menos legível e optaria por usar mais espaços em branco, como já mencionado na resposta de CandiedOrange.

consté uma funcionalidade do próprio código. Você não tornaria a função um não-membro para remover a MyClass::seção da declaração; portanto, não remova oconst

Erdrik Ironrose
fonte
4
Concordo que o snippet que você fornece é menos legível. Isso força o leitor a descobrir o que é MObje o que stré, e certamente levanta as sobrancelhas. É especialmente estranho para os tipos cujos nomes você já tem o controle sobre: Ex Por que você não apenas o nome MyObjectcomo MObjpara começar?
Jason C
3

A legibilidade é uma razão válida para não usar const nos parâmetros?

Não. Omitir constpode alterar a funcionalidade, perder proteções constfornece e pode potencialmente criar código menos eficiente.

É possível manter os objetos de parâmetro inalterados manualmente?

Em vez de gastar tempo formatando manualmente o código

void MyClass::myFunction(const MyObject& obj,const string& s1,const string& s2,const string& s3){
  //
}

Use ferramentas de formatação automática . Escreva a função de acordo com seus requisitos funcionais e permita que a formatação automática lide com a apresentação. O ajuste manual da formatação não é tão eficiente quanto o uso da formatação automática e o tempo economizado para melhorar outros aspectos do código.

void MyClass::myFunction(const MyObject& obj, const string& s1, const string& s2, 
    const string& s3) {
  // 
}
chux - Restabelecer Monica
fonte
-1

Contanto que possível, é melhor manter a const visível. Isso melhora bastante a manutenção do código (sem adivinhações para ver se esse método altera meus argumentos).

Se eu vejo muitos argumentos em um método, isso me obriga a considerar a criação de jaron baseado em projeto (Matriz, Empregado, Retângulo, Conta) que seria muito mais curto, mais fácil de entender (elimina uma longa lista de argumentos para métodos).

caneta preta
fonte
Acordado. Eu hesitava em apontar isso. Assim, "caso extremo".
blackpen 22/09/16
@cmaster Dito isto, às vezes em certos contextos, com certos programadores, ele pode ficar legível. Por exemplo, no caso muito específico de um programa até a cintura nas chamadas da API do Windows, com um leitor acostumado a esse ambiente, coisas como, por exemplo , typedef Point * LPPOINTe typedef const Point * LPCPOINT, embora super desagradáveis, ainda carregam um significado implícito, porque é consistente com as expectativas imediatas no contexto. Mas nunca no caso geral; é apenas uma exceção estranha em que consigo pensar.
Jason C
11
Sim, quando vi a pergunta, "const unsigned long long int" me veio à mente, mas não é um bom candidato obter benefícios por ser "const" ou "reference". O typedef resolve o problema geral de encurtar nomes; mas não parece um bom design ocultar o próprio objetivo das construções de linguagem (como "const") por trás dele.
blackpen 22/09/16