Por que os desenvolvedores de C # newline colchetes de abertura? [fechadas]

44

Passei a maior parte dos últimos anos trabalhando principalmente com C # e SQL. Todo programador com quem trabalhei durante esse tempo costumava colocar a chave de abertura de uma instrução de fluxo de controle ou função em uma nova linha. Assim ...

public void MyFunction(string myArgument)
{
     //do stuff
}

if(myBoolean == true)
{
    //do something
}
else
{
    //do something else
}

Sempre fiquei impressionado com o desperdício de espaço, especialmente nas declarações if / else. E eu sei que existem alternativas nas versões posteriores do C #, como:

if(myBoolean == true)
    //do something on one line of code

Mas quase ninguém os usou. Todo mundo fez o negócio de usar cacheados na nova linha.

Então voltei a fazer JavaScript após uma longa ausência. Na minha memória, os desenvolvedores de JavaScript costumavam fazer exatamente a mesma coisa, mas com todas as novas e sofisticadas bibliotecas e outras coisas, a maioria dos desenvolvedores coloca a chave de abertura após a declaração:

function MyJavaScriptFunction() {
    //do something
}

Você pode ver o sentido disso, porque como o uso de fechamentos e ponteiros de função se tornou popular em JavaScript, ele economiza muito espaço e torna as coisas mais legíveis. Então, eu me perguntava por que não era visto como algo feito em C #. De fato, se você tentar a construção acima no Visual Studio 2013, ela realmente a reformará para você, colocando a chave de abertura em uma nova linha!

Agora, acabei de ver esta pergunta na Code Review SE: https://codereview.stackexchange.com/questions/48035/questions-responses-let-me-tell-you-about-you. Em que aprendi isso em Java, um idioma com o qual eu não estou muito familiarizado, é considerado pouco rigoroso abrir o aparelho logo após a declaração, da maneira moderna do JavaScript.

Eu sempre entendi que o C # era originalmente modelado após o Java e mantinha muitos dos mesmos padrões de codificação basal. Mas, neste caso, parece que não. Então, presumo que deve haver uma boa razão: qual é a razão? Por que os desenvolvedores de C # (e o Visual Studio) impõem a abertura de colchetes em uma nova linha?

Bob Tway
fonte
30
Convenção é simplesmente isso.
Oded
19
O Visual Studio não impõe nada, o estilo do código é configurável. Algo precisa ser o padrão. Qual padrão é "melhor" é o bikeshedding da ordem mais alta.
Phoshi #
23
A chave no final da linha é o antigo padrão K&R C. Kernighan e Ritchie inventaram o idioma C quando os monitores do computador tinham apenas 25 linhas (23 se você adicionar linhas de cabeçalho e status). Não é mais esse o caso, certo? O importante é a consistência em todo o projeto. Também existem estudos científicos que mostram que o suporte em sua própria linha (recuado no mesmo nível do código) de fato melhora a compreensão do código, apesar do que as pessoas pensam que pensam da estética.
Craig
10
O C # sempre apoiou a avaliação de uma única linha de código após um condicional, a propósito. De fato, é a única coisa que faz, mesmo agora. Colocar código entre chaves depois de uma expressão de ramificação apenas torna essa instrução um erro (o compilador cria escopo usando instruções jmp). C ++, Java, C # e JavaScript são mais ou menos baseados em C, com as mesmas regras de análise subjacentes, na maior parte. Portanto, nesse sentido, o C # não é "baseado em Java".
22414 Craig
10
Como uma nota lateral, if(myBoolean == true)faz pouco sentido para mim. Enquanto estamos nisso, enquanto não if ((myBoolean == true) == true)? Apenas if (myBoolean)e isso é o suficiente. Desculpe, uma irritação minha.
precisa saber é o seguinte

Respostas:

67

A chave no final da linha é o antigo padrão K&R C, de Brian Kernighan e Dennis Ritchie, o livro The C Programming Language , que eles publicaram em 1978 após co-inventar o sistema operacional UNIX e a linguagem de programação C (acho que C era projetado principalmente por Ritchie), na AT&T.

Costumava haver guerras de chamas sobre "o único estilo de chave".

Ritchie inventou a linguagem C e Kernighan escreveu o primeiro tutorial, quando as telas do computador mostravam apenas algumas linhas de texto. De fato, o desenvolvimento do UNICS (mais tarde UNIX) começou em um DEC PDP-7, que usava uma máquina de escrever, impressora e fita de papel para uma interface do usuário. O UNIX e C foram finalizados no PDP-11, com terminais de texto de 24 linhas. Portanto, o espaço vertical era de fato um prêmio. Hoje, todos nós temos telas um pouco melhores e impressoras de alta resolução, certo? Quero dizer, eu não sei sobre você, mas tenho três (3) telas de 24 "1080p à minha frente agora. :-)

Além disso, grande parte desse livrinho, The C Programming Language, é um exemplo de código que, ao colocar as chaves no final das linhas, em vez de em suas próprias linhas, economizava uma quantia considerável em impressão.

O que é realmente importante é a consistência em todo o projeto, ou pelo menos em um determinado arquivo de código-fonte.

Também existem estudos científicos que mostram que o suporte em sua própria linha (recuado no mesmo nível do código) melhora a compreensão do código, apesar do que as pessoas pensam que pensam da estética. Isso deixa muito claro para o leitor, visual e instintivamente, qual código é executado em que contexto.

if( true )
    {
    // do some stuff
    }

O C # sempre apoiou a avaliação de um único comando após uma expressão de ramificação, a propósito. De fato, é a única coisa que faz, mesmo agora. Colocar o código entre chaves depois de uma expressão de ramificação apenas faz com que um comando saia (o compilador cria escopo usando instruções jmp). C ++, Java, C # e JavaScript são mais ou menos baseados em C, com as mesmas regras de análise subjacentes, na maior parte. Portanto, nesse sentido, o C # não é "baseado em Java".

Resumindo, isso é um pouco de uma questão religiosa / guerra de chamas. Mas não são estudos tornando-se bastante claro que organizar o código em blocos de melhora humana compreensão. O compilador não se importava. Mas isso também está relacionado à razão pela qual eu nunca coloquei uma linha de código depois de uma ramificação sem chaves - é muito fácil para mim ou outro programador inserir outra linha de código mais tarde e escorregar no fato de que não execute no mesmo contexto com a linha antes ou depois dela.

EDIT : Basta olhar o bug da Applegoto fail para obter um exemplo perfeito desse problema exato, que teve consequências muito graves no mundo real.

if( true )
    doSomething();

torna-se...

if( true )
    doSomething();
    doSomethingElse();

Nesse caso, é doSomethingElse()executado sempre, independentemente do resultado do teste, mas como é recuado para o mesmo nível da doSomething()instrução, é fácil perder. Isso não é realmente discutível; estudos confirmam isso. Esta é uma grande fonte de erros introduzidos no código-fonte durante a manutenção.

Ainda assim, admito que a sintaxe de fechamento do JavaScript parece um pouco boba com chaves em suas próprias linhas ... esteticamente. :-)

Craig
fonte
13
A parte sobre blocos em condicionais é um pouco enganadora. Em C, o condicional sempre tem uma única instrução, mas um bloco (também conhecido como instrução composta) é um tipo de instrução . C # segue esse precedente. De qualquer forma, a avaliação condicional sempre implica algum tipo de instrução condicional de goto ou ramificação, devido à natureza linear de todos os conjuntos de instruções comuns. Uma condicional sem bloco não é qualitativamente diferente de uma condicional com um bloco (exceto no que diz respeito ao escopo).
amon
3
@ Craig, lembre-se, isso foi no Bell Labs, quando o Bell Labs foi contratado para "fazer coisas interessantes" que não eram necessariamente necessárias para serem práticas para qualquer coisa. Coloque pessoas inteligentes em um prédio, diga-lhes para fazer uma pesquisa interessante, mova-as para fora do que fazem não é "interessante" e, engraçado, coisas INTERESSANTES (como transistores e Unix) tendem a aparecer. A DARPA tinha o mesmo foco, no começo, e eles financiaram MUITO bom trabalho, em nome da pesquisa básica.
precisa saber é o seguinte
3
@ Craig: Nos velhos tempos de Pascal / Delphi, eu normalmente evitava blocos de linha única, como o Pascal usa begine endno lugar de chaves, o que dificulta a falta desses erros, além de ser mais rigoroso quanto à colocação de ponto-e-vírgula - mas gastar 4 dias no ano passado, depurando um problema no C incorporado, que acabou sendo devido à falta de colocação de chaves de alguém ..... Acho que deveria haver uma opção de compilador que torna as chaves obrigatórias para instruções de controle!
Mark K Cowan
12
Por favor, forneça referências para "... estudos científicos mostrando que o suporte em sua própria linha ...". Sem pelo menos duas referências (caso contrário, seria estudo , não estudos ), é apenas um tiro aleatório no ar.
ErikE
2
@ Craig, você poderia fornecer algumas pistas sobre como encontrar os estudos de pesquisa mencionados?
Grzegorz Adam Kowalski
30

A razão pela qual os desenvolvedores de C # fazem isso é porque é a configuração padrão do formatador automático do Visual Studio. Embora essa configuração possa ser alterada, a maioria das pessoas não, e, portanto, todos os desenvolvedores de uma equipe precisam ir com a maioria.

Por que esse é o padrão no Visual Studio, eu não sei.

Timwi
fonte
15
É o padrão no Visual Studio, porque era o estilo de codificação geralmente aceito na Microsoft há muito tempo e, de fato, em pelo menos algumas equipes da Microsoft o estilo não era apenas aparelho em suas próprias linhas, mas em suas próprias linhas. e recuado. Portanto, também é uma opção no Visual Studio (eu pessoalmente prefiro).
Craig
20
@Craig: Ewwwwwwwww
Lightness Races com Monica
5
@PreferenceBean Hmm. Pessoalmente, eu não gosto do estilo K&R, porque os colchetes são perdidos no barulho no final das linhas e o texto parece desajeitado para mim, o que não é apenas uma preferência estética, mas tem um impacto real na legibilidade / compreensão. Eu gosto de espaço em branco vertical. Era um pouco diferente em monitores de 12 "com 24 linhas de texto nos velhos tempos em que o espaço vertical era precioso.
Craig
10
@Craig: Isso não é desculpa para recuar o aparelho: P
Lightness Races with Monica
2
@ Craig Para tornar os funcionários da Microsoft miseráveis?
Mateen Ulhaq
18

Como eu hipotetizei nesta resposta aqui - https://softwareengineering.stackexchange.com/a/159081/29029 - Suponho que a decisão de usar o suporte de Allman possa ser um sinal da herança Pascal, já que Hejlsberg criou o Delphi antes de projetar o C # . O mesmo que Pascal para nomes de métodos.

Pessoalmente, acredito em seguir o ditado "em Roma, como os romanos". Eu uso Allman em C #, mas K&R em Java. Estou tão acostumado a isso que mudar a convenção de qualquer maneira é chocante para mim.

Acredito que alguma diversidade de convenções é realmente benéfica para um desenvolvedor "multilíngue", pois ajuda a lembrar em qual idioma eles estão codificando no momento e facilita a diferenciação de vários hábitos. É um equivalente mental da memória muscular, por assim dizer.

Konrad Morawski
fonte
7
+1 para a linha "desenvolvedor multilíngue", na verdade. Eu seriamente prefiro suspensórios em suas próprias linhas e recuados. No entanto, no trabalho em, por exemplo, projetos ASP.NET (MVC), acho que gosto de C # com o estilo "certo" e JavaScript com o estilo "JavaScript". Isso é um pouco irônico, mas honestamente parte disso é que a sintaxe de fechamento do JavaScript é mais atraente com a chave no final da linha. Então, eu sou tanto um escravo para a estética como qualquer outra pessoa ...
Craig
O PascalCase para nomes de métodos era um padrão na Microsoft muito tempo antes de Anders Hejlsberg deixar a Borland para ser um destacado engenheiro de software da Microsoft.
30717 Craig
2
Curiosamente, eu uso o Allman para todos os idiomas de chaves. No entanto, estou me interessando cada vez mais com a aparência de uma conversão de pré-processamento de recuos em blocos de chaves em Java. O código "java" pode ser extremamente limpo, uma vez que envolvi minha mente de reconhecimento de padrões em torno dele. Eu acho que o Python pode realmente ter razão: não há realmente uma grande razão para chaves em uma linguagem.
tgm1024
Usar espaço em branco para controlar o fluxo do programa é insanidade. O Python é popular hoje em dia, mas esse aspecto do Python ficou um pouco louco desde que apareceu pela primeira vez.
Craig
@Craig Python fã aqui, tentando fazer algo em javascript. Observando sua outra resposta e sua edição sobre o goto fail, usar o recuo para controlar o fluxo do programa é o que os humanos naturalmente querem fazer; portanto, o que você vê é o que é executado. Se estiver indentado errado, simplesmente não funciona. Ter que decodificar o que esses aparelhos significam, se eles realmente refletem o recuo, é um trabalho adicional além da compreensão do programa. O recuo é redundante para chaves, então por que os programadores a usam se as chaves são úteis? O aninhamento profundo é ininteligível em qualquer idioma. Só estou dizendo.
31418 Neil_UK
14

A convenção que você associa ao Java é o estilo K&R, ou "Um estilo de chave verdadeira", e vem originalmente de C. Esta página no estilo de recuo do venerável arquivo Jargon mostra a idade da distinção.

Eu sempre pensei que o estilo Allman e suas variantes são um reflexo de como os autores pensam sobre o código, elevando os delimitadores de bloco ao nível de palavras-chave semelhantes a como algumas linguagens usam "begin" e "end" em torno de blocos de código.

John Bickers
fonte
Tenho a impressão de que hoje em dia o OTBS (um estilo de colchete verdadeiro) também implica nunca deixar de fora os colchetes após as instruções de controle, mesmo para linhas de código únicas. Veja o bug da Apple para falha.
Craig