Quais são alguns limites estilísticos razoáveis ​​na inferência de tipo?


8

O C ++ 0x adiciona um suporte bastante abrangente a inferência de tipos. Estou extremamente tentado a usá-lo em todos os lugares possíveis para evitar repetições indevidas, mas estou me perguntando se a remoção de informações explícitas de tipo em todo o lugar é uma boa idéia. Considere este exemplo bastante artificial:

Foo.h:

#include <set>

class Foo {
private:

    static std::set<Foo*> instances;

public:

    Foo();
    ~Foo();

    // What does it return? Who cares! Just forward it!
    static decltype(instances.begin()) begin() {
        return instances.begin();
    }

    static decltype(instances.end()) end() {
        return instances.end();
    }

};

Foo.cpp:

#include <Foo.h>
#include <Bar.h>

// The type need only be specified in one location!
// But I do have to open the header to find out what it actually is.
decltype(Foo::instances) Foo::instances;

Foo() {

    // What is the type of x?
    auto x = Bar::get_something();

    // What does do_something() return?
    auto y = x.do_something(*this);

    // Well, it's convertible to bool somehow...
    if (!y) throw "a constant, old school";

    instances.insert(this);

}

~Foo() {
    instances.erase(this);
}

Você diria que isso é razoável ou é completamente ridículo? Afinal, especialmente se você está acostumado a desenvolver em uma linguagem dinâmica, não precisa se preocupar muito com os tipos de coisas e pode confiar que o compilador detectará qualquer abuso flagrante do sistema de tipos. Mas para aqueles que dependem do suporte do editor para assinaturas de métodos, você está sem sorte; portanto, usar esse estilo em uma interface de biblioteca é provavelmente uma prática muito ruim.

Acho que escrever coisas com todos os tipos possíveis implícitos, na verdade, facilita muito o meu código, porque remove quase toda a desordem usual do C ++. Sua milhagem pode, é claro, variar, e é sobre isso que estou interessado em ouvir. Quais são as vantagens e desvantagens específicas do uso radical da inferência de tipo?


Na verdade, você fazer necessidade de cuidados sobre os tipos se você está em desenvolvimento em uma linguagem dinâmica; se você tiver o tipo de algo errado, não descobrirá até atingir essa seção do código em tempo de execução.
— Larry Coleman

@ Larry: Claro. Mas não no sentido em que você precisa prever o tipo exato e a cadeia de herança de cada objeto em uso.

Respostas:


5

Sendo principalmente um programador Python, compartilho a mentalidade de que o programador não precisa saber o tipo exato. No caso de C ++, especialmente quando se lida com modelos de modelos com modelos ... É claro que isso não acontece porque detesto a digitação estática (não considero - considero Haskell uma das melhores coisas desde o pão fatiado, em parte devido à sua digitação estática), mas porque não me importo com o tipo exato. Por que, não é bem demonstrado por exemplos que usam nomes como fooou get_stuff(). Então, vamos escolher algo mais próximo da realidade:

auto users = get_users();
vector<decltype(users[0])> blocked_users;
/* I'm not a C++ guru, much less C++0x so forgive me if type
   inference and foreach must be combined differently */
for (auto user : users) {
    if (check_name(user.name)) blocked_users.push_back(user)
}

Não é uma anotação de tipo único, mas é perfeitamente claro o que faz, certo? Esse código não se importa com o tipo users, apenas precisa de algum intervalo para iterar sobre o que contém itens com os namequais pode ser alimentado check_name. Nada mais. Ninguém se importa com os 100-ish caracteres dos nomes de tipo que você teria que digitar de outra forma.

O mesmo se aplica à maioria dos códigos com nomes significativos. O exemplo da pergunta não é claro, mas também não seria claro com nomes de tipo explícitos, porque nem o contexto nem os identificadores fornecem qualquer indicação do que está acontecendo. Use identificadores significativos e o código pode ser entendido independentemente das anotações de tipo explícitas.


3

A razão pela qual eles trouxeram inferência foi impedir que as pessoas escrevessem códigos como:

foo().bar().baz().etc();

Quando você poderia escrever:

Foo f = foo();
Bar b = f.bar();
...

Exceto que Foo seria algum tipo de modelo longo, então torna-se melhor escrever:

auto f = foo();
auto b = f.bar();
...

Portanto, como regra geral, se o uso de auto faz com que você escreva o código como acima, em vez de um código semelhante ao primeiro exemplo, use-o. Caso contrário, continue adicionando definições explícitas.


Faz sentido. Eu me vejo usando autoem muitos casos em que tenho certeza de que outros seriam explícitos, mas não vejo o que há realmente de errado, por exemplo auto f = new SomethingLong(), porque é óbvio o que a expressão retorna. Eu só estou me perguntando onde traçar a linha.
— Jon Purdy

Tudo bem se SomethingLongnão fizer parte de nenhuma estrutura de herança, mas, a menos que você tenha certeza de que nunca será, aconselho isso. É muito mais fácil traçar a linha do lado cauteloso.
— dan_waterworth

2

Existem boas razões para nem sempre usar a inferência de tipo. Haskell tem inferência de tipo, mas geralmente declaro explicitamente os tipos de função. Isso é parcialmente resultado do meu estilo de desenvolvimento. Declaro a função primeiro:

myFunction :: [Int] -> Int
myFunction xs = undefined
Em seguida, vou escrever o código que usa essa função e fazer uma compilação para garantir que digite as verificações. Depois de digitar as verificações, irei adiante com a implementação.

A outra razão para declarar tipos de função é que as declarações podem servir como documentação adicional. Que esta documentação seja verificada em todas as compilações é um bônus.


2
Embora a abordagem do tipo primeiro seja muito elegante em Haskell, duvido que seja adequada para C ++. Sem conceitos , uma assinatura de modelo C ++ basicamente não diz nada - é a implementação que define os tipos e argumentos de requisitos a serem cumpridos. Os modelos simplesmente digitam em tempo de compilação - "tente e veja se funciona". Assim, eu diria que podemos estar implícitos com os tipos, assim como as linguagens dinâmicas tipadas por patos também.
— Dario
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.