Uncategorized

Prós e contras da sintaxe alternativa do C++

No mundo da programação nós podemos classificar as linguagens de duas maneiras: Linguagem de Baixo Nível e Linguagem de Alto Nível. Quando nos referimos à linguagem de Baixo Nível estamos nos referindo a sintaxes próximas ao código de maquina, ou seja, a linguagem que o computador consegue facilmente interpretar. Em contrapartida a definição de linguagem de Baixo Nível nós encontramos as linguagem de Alto Nível, com relação a esse tipo de linguagem podemos afirmar que a mesma possui uma sintaxe próxima à linguagem humana um exemplo desse tipo de linguagem é o próprio C++.

Para ter uma ideia de como é desenvolver em C++, assista à aula do livecoder DenisJose12 sobre estruturas de dados em C++:

O C++ foi inicialmente desenvolvido por Bjarne Stroustrup dos Bell Labs durante a década de 1980 (originalmente com o nome C with Classes, como um adicional à linguagem C) com o objectivo de melhorar a linguagem de programação C ainda que mantendo máxima compatibilidade. Em 1983 o nome da linguagem foi alterado de C with Classes para C++, novas características foram adicionadas, como funções virtuais, sobrecarga de operadores e funções, referências, constantes, gerenciamento manual de memória, melhorias na verificação de tipo de dado e estilo de comentário de código de uma linha (//).

Para aprender mais sobre C++, confira este curso gratuito e com certificado sobre desenvolvimento orientado a objeto em C++ da fundação Bradesco que a CBSI separou.

Após a padronização ISO realizada em 1998 e a posterior revisão realizada em 2003, uma nova versão da especificação da linguagem foi lançada em setembro de 2011, conhecida informalmente como C++11 ou C++0x. Este novo padrão incluirá muitas adições ao núcleo da linguagem (sua implementação principal), e estenderá a biblioteca padrão do C++, incluindo a maior parte da biblioteca do chamado C++ Technical Report 1 — um documento que propõe mudanças ao C++ — com exceção das funções matemáticas específicas.

C++11 introduziu uma sintaxe alternativa para escrever declarações de função. Em vez de colocar o tipo de retorno antes do nome da função (por exemplo, int func () ), a nova sintaxe permite escrever após os parâmetros (por exemplo, auto func () -> int ). Isso leva a duas perguntas: Por que uma sintaxe alternativa foi adicionada? Ela vai substituir a sintaxe original do C++? Para ajudá-lo com essas perguntas, vamos resumir as vantagens e desvantagens desta sintaxe recém-adicionada.

Introdução

Desde o C++11, temos uma nova maneira de declarar funções. Esta sintaxe alternativa nos permite escrever a seguinte função:

// C or C++98

int f(int x, int y) {

   // ...

}

Como

// C++11

auto f(int x, int y) -> int {

   // ...

}

Basicamente, em vez de escrever o tipo de retorno antes do nome da função, nós colocamos apenas auto e especificamos o tipo de retorno após a lista de parâmetros. Uma vez que o tipo de retorno aparece no final da declaração, diz-se que a função tem um tipo de retorno à direita. Ambas as declarações acima são equivalentes, o que significa que elas significam exatamente o mesmo.

Nota: o uso do auto aqui é apenas parte da sintaxe e não executa dedução de tipo automática neste caso. A dedução automática foi adicionada no C++14, e teria o seguinte efeito se não fornecêssemos o tipo de retorno de retorno:

// C++14

auto f(int x, int y) {

    // The return type is deduced automatically

    // based on the function's body.

    // ...

}

Prós

Simplificação do Código Genérico

Considere a seguinte função, escrita usando a sintaxe alternativa:

// C++11

template<typename Lhs, typename Rhs>

auto add(const Lhs& lhs, const Rhs& rhs) -> decltype(lhs + rhs) {

    return lhs + rhs;

}

A função tem dois parâmetros e retorna sua soma. Note que os parâmetros podem ter diferentes tipos, razão pela qual usamos dois parâmetros de modelo diferentes. Contanto que os tipos suportam binário +, eles podem ser usados como argumentos para add(). O especificador decltype nos dá o tipo da expressão lhs + rhs.

Vamos tentar reescrever a função usando a sintaxe padrão:

template<typename Lhs, typename Rhs>

decltype(lhs + rhs) add(const Lhs& lhs, const Rhs& rhs) {

   // error: ^^^ 'lhs' and 'rhs' were not declared in this scope

   return lhs + rhs;

}

Oops! Uma vez que o compilador analisa o código-fonte da esquerda para a direita, o compilador verá lhs e rhs antes de suas definições e rejeita o código. Usando o tipo de retorno à direita, podemos contornar essa limitação.

Nota: a função acima pode ser escrita usando a sintaxe padrão com a ajuda de declval():

Template <typename Lhs, typename Rhs>

Declty (std :: declval <Lhs> () + std :: declval <Rhs> ()) add (const Lhs & lhs, const Rhs & rhs) {

    Return lhs + rhs;

}

No entanto, como você pode ver, torna o código menos legível.

Eliminação de Repetição

Considere a seguinte classe:

class LongClassName {

   using IntVec = std::vector<int>;

   IntVec f();

};

Para definir f() usando a sintaxe padrão, temos que duplicar o nome da classe:

LongClassName::IntVec LongClassName::f() {

    // ...

}

O motivo é semelhante ao do exemplo anterior: O compilador analisa o código da esquerda para a direita, por isso, se o compilador viu IntVec, não soube onde procurá-lo porque o contexto (LongClassName) é dado após o tipo de retorno. Com a nova sintaxe, não há necessidade de repetir LongClassName:

auto LongClassName::f() -> IntVec {

    // ...

}

Consistência

Por último, mas certamente não menos importante, o uso uniforme da nova sintaxe pode levar a um código mais consistente. Por exemplo, quando você define uma expressão lambda, seu tipo de retorno pode ser especificado apenas como o tipo de retorno à direita:

[](int i) -> double { /* ... */ };

Não existe uma sintaxe de tipo de retorno “antiga” para expressões lambda, portanto, não é possível escrever o tipo de retorno no lado esquerdo.

De forma mais geral, como apontado por Herb Sutter, o mundo C ++ está indo para um estilo de declaração da esquerda para a direita em todos os lugares, na forma nome da categoria = tipo e/ou inicializador, em que a categoria pode ser auto ou using. Exemplos:

auto hello = "Hello"s;

auto f(double) -> int;

using dict = std::map<std::string, std::string>;

Finalmente, uma propriedade um tanto agradável da nova sintaxe é que as declarações de funções agora estão ordenadamente alinhadas por seu nome:

auto vectorize() -> std::vector<int>;

auto devour(Value value) -> void;

auto get_random_value() -> Value;

No entanto, o alinhamento de nomes de funções parece mais legível apenas quando as funções levam uma linha cada.

Contras

Omissão pode causar uma cópia a ser devolvida

No C++14, se você esquecer de especificar o tipo de retorno à direita, um tipo de retorno será deduzido automaticamente. Infelizmente, o tipo deduzido pode não ser o que você quer. Por exemplo, considere a seguinte definição padrão de um operador de atribuição:

auto MyClass::operator=(const MyClass& other) -> MyClass& {
    value = other.value;
    return *this;
}

Se você omitir o tipo de retorno à direita, o código será compilado, mas ele retornará um valor em vez de uma referência:

auto MyClass::operator=(const MyClass& other) {
    value = other.value;
    return *this; // Oops, returns a copy of MyClass!
}

Na verdade, a dedução de tipo automático via auto nunca deduz uma referência (se você quiser uma referência, use auto& em vez). Uma omissão descuidada pode assim mudar silenciosamente a semântica do seu código.

Pode produzir declarações mais longas

Às vezes, a nova sintaxe produz declarações mais longas:

int func();
// vs
auto func() -> int;

Posição inesperada com Override

Independente da experiência, já vimos pessoas atingidas por isso. Considere o seguinte código:

struct A {
    virtual int foo() const noexcept;
};
 
struct B: A {
    virtual int foo() const noexcept override

Algumas pessoas esperam que a declaração de B::foo() com a nova sintaxe seja assim:

virtual auto foo() const noexcept override -> int;
// error: virtual function cannot have deduced return type

Oops! A forma correta é:

virtual auto foo() const noexcept -> int override;

Ou seja, override tem de ser especificado após o tipo de retorno à direita.

Consistência

Se você ainda se lembra da lista de prós, você deve se lembrar que a consistência era um dos prós. No entanto, isso só se aplica ao novo código. A maior parte do código existente foi escrito usando a sintaxe padrão. Assim, quando você começar a usar o novo estilo, seu estilo de codificação pode realmente se tornar inconsistente.

Não é um recurso amplamente conhecido

Em geral, os programadores não estão familiarizados com a nova sintaxe. Embora isso não seja uma razão contra a nova sintaxe, é algo deve ser lembrado. Para as pessoas que programam em C e C ++ por muito tempo, a nova sintaxe parece estranha. Então, pense duas vezes antes de escrever

auto main() -> int {}

já que isso pode fazer que seus colegas de trabalho queiram bater-lhe com uma vara 🙂

Conclusão

A sintaxe alternativa foi adicionada para auxiliar a escrita de código genérico e para fornecer consistência. No entanto, devido às várias desvantagens listadas acima, a sintaxe original é usada mais amplamente do que a nova sintaxe. Até mesmo as diretrizes do C++ usam a sintaxe original.

 

Dr. Michael J. Garbade

I, Dr. Michael J. Garbade is the co-founder of the Education Ecosystem (aka LiveEdu), ex-Amazon, GE, Rebate Networks, Y-combinator. Python, Django, and DevOps Engineer. Serial Entrepreneur. Experienced in raising venture funding. I speak English and German as mother tongues. I have a Masters in Business Administration and Physics, and a Ph.D. in Venture Capital Financing. Currently, I am the Project Lead on the community project -Nationalcoronalvirus Hotline I write subject matter expert technical and business articles in leading blogs like Opensource.com, Dzone.com, Cybrary, Businessinsider, Entrepreneur.com, TechinAsia, Coindesk, and Cointelegraph. I am a frequent speaker and panelist at tech and blockchain conferences around the globe. I serve as a start-up mentor at Axel Springer Accelerator, NY Edtech Accelerator, Seedstars, and Learnlaunch Accelerator. I love hackathons and often serve as a technical judge on hackathon panels.

Recent Posts

Blockchain in Elections: A Leap Toward Transparent Democracy

In 2024 we're witnessing a critical point in democratic technology: the integration of blockchain and…

3 weeks ago

Win Big with Our Amazon Fire Max 11 & AirPods Pro Giveaway!

We’re thrilled to announce an exciting opportunity for you to win not one but two…

2 months ago

Unleashing Potential: How Education Ecosystem Transforms Learning into Real-World Success

Acquiring practical skills is crucial for career advancement and personal growth. Education Ecosystem stands out…

4 months ago

The Role of Artificial Intelligence in Modern Software Development

Artificial Intelligence (AI) has been making significant strides in various industries, and the software development…

7 months ago

Highest Stable Coin Yields – (W16 – 2024)

Another week to bring you the top yield platforms for three of the most prominent…

8 months ago

LEDU Token OTC Trading

If you hold a large volume of LEDU tokens above 1 million units and wish…

9 months ago