Quali sono alcuni limiti stilistici ragionevoli per l'inferenza di tipo?

7

C ++ 0x aggiunge un supporto inferenziale di tipo completo e dannatamente completo. Sono strongmente tentato di usarlo ovunque possibile per evitare ripetizioni ingiustificate, ma mi chiedo se la rimozione di informazioni di tipo esplicito dappertutto sia una buona idea. Considera questo esempio piuttosto forzato:

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);
}

Diresti che è ragionevole o è completamente ridicolo? Dopotutto, specialmente se sei abituato a sviluppare in un linguaggio dinamico, non devi aver bisogno di preoccuparti di tutto ciò che riguarda i tipi di cose, e puoi avere fiducia che il compilatore catturerà qualsiasi egregio abusi del sistema di tipo. Ma per quelli di voi che si affidano al supporto dell'editor per le firme dei metodi, si è sfortunati, quindi usare questo stile nell'interfaccia di una libreria è probabilmente una cattiva pratica.

Trovo che scrivere cose con tutti i tipi possibili impliciti rende il mio codice molto più facile da seguire, perché rimuove quasi tutto il solito ingombro di C ++. Il tuo chilometraggio può, ovviamente, variare, ed è quello che mi interessa sapere. Quali sono i vantaggi e gli svantaggi specifici dell'uso radicale dell'inferenza di tipo?

    
posta Jon Purdy 07.01.2011 - 07:35
fonte

3 risposte

4

Essendo io stesso principalmente un programmatore Python, condivido la mentalità che il programmatore non ha bisogno di conoscere esattamente il tipo. Nel caso di C ++, specialmente quando si tratta di modelli basati su modelli basati su modelli. Certo che non è perché disprezzo la digitazione statica (non lo faccio - considero Haskell una delle cose migliori dal pane affettato, in parte a causa della sua tipizzazione statica), ma perché non mi interessa il tipo esatto. Perché, non è dimostrato bene dagli esempi che usano nomi come foo o get_stuff() . Quindi scegliamo qualcosa più vicino alla realtà:

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)
}

Non una singola annotazione di tipo, ma è perfettamente chiaro che cosa fa, giusto? Questo codice non interessa quale sia il tipo di users , ha solo bisogno di un intervallo per iterare su cui contiene cose con un name che può essere inviato a check_name . Niente di più. A nessuno importa dei 100 caratteri dei nomi di tipo che dovresti digitare altrimenti.

Lo stesso vale per la maggior parte del codice con nomi significativi. L'esempio nella domanda non è chiaro, ma non sarebbe chiaro nemmeno con nomi di tipo espliciti, perché né il contesto né gli identificatori forniscono alcuna indicazione su cosa sta succedendo. Utilizza identificatori significativi e il codice può essere compreso indipendentemente dalle annotazioni di tipo esplicito.

    
risposta data 07.01.2011 - 09:54
fonte
2

Il motivo per cui hanno portato l'inferenza è stato quello di impedire alle persone di scrivere codice come:

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

Quando potresti scrivere:

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

Tranne Foo sarebbe un tipo di modello lungo, quindi diventa più carino scrivere:

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

Quindi, come regola generale, se usare auto ti fa scrivere codice come sopra invece di codice simile al primo esempio, allora usa con tutti i mezzi. Altrimenti, attenersi ad aggiungere definizioni esplicite.

    
risposta data 07.01.2011 - 09:14
fonte
2

Ci sono buone ragioni per non usare sempre l'inferenza di tipo. Haskell ha inferenza di tipo, ma di solito dichiaro esplicitamente i tipi di funzione in ogni caso. Questo è in parte il risultato del mio stile di sviluppo. Dichiaro prima la funzione:

myFunction :: [Int] -> Int
myFunction xs = undefined
Successivamente, scriverò il codice che usa quella funzione e faccio una compilazione per assicurarmi che scriva i controlli. Una volta digitati i controlli, procederò con l'implementazione.

L'altro motivo per dichiarare i tipi di funzione è che le dichiarazioni possono servire come documentazione aggiuntiva. Che questa documentazione sia verificata su ogni compilazione è un bonus.

    
risposta data 07.01.2011 - 20:49
fonte

Leggi altre domande sui tag