PIMPL: Doppeländerung der Deklarationen umgehen?



  • Die Zeit die du für diesen Thread aufgewendet hast, reicht für locker 2-3 Monate pimpl Deklarationen zu verdoppeln.

    Tipparbeit ersparen zu wollen ist fast immer eine schlechte Idee.

    Probier mal die Klasse erst zu pimpeln wenn das Interface stabil geworden ist. Denn pimpl ist ja genau dafür da: stabiles interface, instabile implementierung.

    Wenn du ein instabiles Interface hast, was bringt dir pimpl denn dann?



  • Shade Of Mine schrieb:

    Die Zeit die du für diesen Thread aufgewendet hast, reicht für locker 2-3 Monate pimpl Deklarationen zu verdoppeln.

    Tipparbeit ersparen zu wollen ist fast immer eine schlechte Idee.

    +1

    Shade Of Mine schrieb:

    Probier mal die Klasse erst zu pimpeln wenn das Interface stabil geworden ist. Denn pimpl ist ja genau dafür da: stabiles interface, instabile implementierung.

    Wenn du ein instabiles Interface hast, was bringt dir pimpl denn dann?

    Dass man es nicht vergisst 🙂

    @Eisflamme
    Ich schreibe immer class. Ich mache aber auch meist die "alles durchreichen" Variante. Weil ich es "bäh" finde wenn man bei jedem Member-Zugriff m_impl-> schreiben muss.
    Wenn ich es allerdings so mache, dann schreib ich trotzdem class nur halt in der Implementierung dann als 1. Zeile public: .
    Oder, was ja IIRC auch erlaubt ist (MSVC frisst es zumindest), du deklarierst mit class und definierst dann aber mit struct . Wobei die eine diese public: Zeile die man dadurch spart die "Unschönheit" dieser Lösung vermutlich nicht rechtfertigt.



  • Shade Of Mine schrieb:

    Probier mal die Klasse erst zu pimpeln wenn das Interface stabil geworden ist. Denn pimpl ist ja genau dafür da: stabiles interface, instabile implementierung.

    Wenn du ein instabiles Interface hast, was bringt dir pimpl denn dann?

    Wahre Worte, allerdings gibt noch einen Anwendungsfälle wo man direkt lospimpln möchte (ich zumindest):
    z.B. Wenn man es mit unsäglichen Headern wie z.B. windows.h zu tun hat, die sich wie ein Elefant im Porzellanladen aufführen.
    Ist nicht verkehrt die direkt in einem PIMPL-Käfig einzusperren, damit sie nicht den ganzen Code verpesten (Spass mit std::numeric_limits<T>:max() , etc., etc.).

    Finnegan



  • Eisflamme schrieb:

    Hi,

    wenn ich bei PIMPL in der public-Klasse eine Methode hinzufüge, reicht die ja fast immer nur den Aufruf zur private-Klasse durch. In selbiger benötige ich dieselben Funktionsdeklarationen und muss alles doppelt schreiben. Änderungen sind doppelt, neue Methoden sind doppelt, Löschungen müssen doppelt gemacht werden.

    Das stört mich. Hat das Problem jemand von euch gelöst?

    ja, ein Interface einführen welches dann von der äußeren und der inneren Klasse verwendet wird.
    dann schreibst du alles 3x.
    Triffst du dann auf eine Klasse die kein Interface mehr braucht, kommt dir 2x richtig wenig vor.

    Spass beiseite, wozu?
    wenn man libraries schreibt und ausliefern will und das ABI nicht brechen will kann man so etwas vorbauen, ok, das ist aber weniger oft der Fall als man denkt.

    wozu noch?



  • Okay, danke 🙂 Das gibt mir ein paar gute Eindrücke. Dann werde ich das künftig etwas anders handhaben



  • hustbaer schrieb:

    Shade Of Mine schrieb:

    Die Zeit die du für diesen Thread aufgewendet hast, reicht für locker 2-3 Monate pimpl Deklarationen zu verdoppeln.

    Tipparbeit ersparen zu wollen ist fast immer eine schlechte Idee.

    +1

    ++1

    Ein Vorteil von pimpl ist, dass die Interfaces der inneren und äussere Klasse unterscheiden können.

    Bei der inneren Klasse mache ich ein möglichst minimales Interface, welches technisch effizient und leicht wartbar ist. In der äusseren Klasse kann ich zig helper anbieten, welche die Benutzung einfach macht.

    Natürlich ist das Tipparbeit, aber ist das Tippen wirklich das, was uns Entwicklern die meiste Zeit nimmt? Ich denke nicht.



  • Finnegan schrieb:

    z.B. Wenn man es mit unsäglichen Headern wie z.B. windows.h zu tun hat, die sich wie ein Elefant im Porzellanladen aufführen.
    Ist nicht verkehrt die direkt in einem PIMPL-Käfig einzusperren, damit sie nicht den ganzen Code verpesten (Spass mit std::numeric_limits<T>:max() , etc., etc.).

    Ich gebe dir zwar prinzipiell recht, oft helfen aber auch einzelne defines dafür: http://stackoverflow.com/questions/1394910/how-to-tame-the-windows-headers-useful-defines

    NOMINMAX verhindert zB dass die windows.h min und max definiert.



  • Natürlich ist das Tipparbeit, aber ist das Tippen wirklich das, was uns Entwicklern die meiste Zeit nimmt? Ich denke nicht.

    Tipp- und Doppelarbeit zeigt Ineffizienz und bietet Möglichkeiten Fehler zu machen. Das kostet nicht selbst Zeit, aber wenn ich merke, dass ich irgendwo ineffizient bin, habe ich automatisch den Fehler etwas "unschön" oder "unsauber" gemacht zu haben, was meine Motivation und damit meine Entwicklungsgeschwindigkeit hemmt.

    Ich widerspreche der Aussage "Tipparbeit sparen ist fast immer eine schlechte Idee" übrigens vehement.

    Denn mit dem Sparen von Tipparbeit erarbeitet man sich oft noch eine Menge anderer Vorteile. Beispielsweise nutze ich typedef s, um nicht jedes mal std::vector<MyType>::const_iterator schreiben zu müssen. Der Hauptvorteil davon ist doch - seien wir ehrlich -, dass ich Tipparbeit spare. using namespace dient auch dazu Tipparbeit zu sparen, was einige in ihren cpps anscheinend ja gar nicht nutzen, aber dann viel Spaß damit jedes mal std::placeholders::_1 zu schreiben. Ich weiß nicht, ob hier jemand Autovervollständigung nutzt, aber das dient auch nur dazu Tipparbeit zu sparen. Eine schlechte Idee? Ich denke nicht.

    Kürzerer Code mit gleichem Inhalt und sonst gleicher Lesbarkeit, kann vom Gehirn schneller verarbeitet werden, ist daher leichter zu verstehen, lässt Bugs schneller erkennen und ist auch leichter zu erweitern.

    Ich würde andersrum formulieren: Wenn man Tipparbeit sparen kann ohne dadurch andere Nachteile zu erkaufen, so sollte man das immer tun.



  • Es geht nicht um Tipparbeit. Je mehr ich tippe, desto länger wird mein Code und desto mehr muss ich beim lesen erfassen, um den Code zu verstehen. Daher ist der Grund, etwas kompakt darzustellen, die Lesbarkeit zu erhöhen und nicht, Tipparbeit zu sparen.

    Ein std::vector<MyType>::const_iterator mit einem Typedef zu definieren ist sinnvoll, da der voll qualifizierte Bezeichner doch unübersichtlich und schwer zu erfassen ist.

    Variablennamen wie a , b oder ähnliches sparen Tipparbeit. Dabei leidet aber die Lesbarkeit. Daher bevorzuge ich aussagekräftige Namen, auch wenn ich da ein wenig mehr Tippen muss.

    Doppelarbeit ist sicher ineffizient. Wer doppelte Arbeit machen muss, macht was falsch. Das sollte klar sein.

    Ich bleibe bei der Meinung, dass Tipparbeit zu sparen kein Argument für eine Programmiertechnik sein darf.



  • Das ist halt eine begriffliche Frage, aber unsere Auffassungen unterscheiden sich nach meiner Formulierung ja nicht. "a" statt einem aussagekräftigen Namen wäre ein Nachteil, den man durch Einbüßen von Tipparbeit in Kauf nehmen würde.

    Wer Doppelarbeit macht, macht was falsch? Genau das tut man bei PIMPL, wenn man Methodenaufrufe in der äußeren Klasse an die innere weiterreicht. Im Grunde erscheint es mir immer als Doppelarbeit oder ineffizient, wenn ich weite Teile copy&pasten kann/muss.

    Tipparbeit zu reduzieren heißt schlankerer Code. Wie soll der Code denn entstehen, wenn nicht durch tippen?



  • Shade Of Mine schrieb:

    Ich gebe dir zwar prinzipiell recht, oft helfen aber auch einzelne defines dafür: http://stackoverflow.com/questions/1394910/how-to-tame-the-windows-headers-useful-defines

    NOMINMAX verhindert zB dass die windows.h min und max definiert.

    Eigentlich gefällt es mir nicht so wirklich nur wegen dämlichen Makros auf eine zusätzliche Pointer-Dereferenzierung auszuweichen, allerdings war das bisher immer die effizienteste Methode ein für allemal seine Ruhe zu haben.
    Es sind ja nicht nur min und max , sondern auch noch eine Reihe andere Namen, die man gerne selbst verwenden möchte, z.B. als Variablen oder in enum s. Spass hatte ich bisher u.a. noch mit:

    far , near , small , rad1 , IN , OUT , CALLBACK , ERROR und STATUS_TIMEOUT

    Irgendwann hatte ich dann genug davon und mich für die PIMPL-Isolationshaft entschieden :D.
    Ich gebe allerdings zu, dass ein #define NOMINMAX (und andere) gefolgt von einer #undef -Orgie wahrscheinlich effizienter sind - das kann allerdings andere Nebenwirkungen haben, und Windows-Funktionen werden meist nicht so kritisch eingesetzt,
    dass die zusätzliche Dereferenzierung wirklich einen Unterschied macht.

    Finnegan



  • tntnet schrieb:

    Ein std::vector<MyType>::const_iterator mit einem Typedef zu definieren ist sinnvoll, da der voll qualifizierte Bezeichner doch unübersichtlich und schwer zu erfassen ist.

    Das is so ne Sache...

    Der ausgeschriebene Typ ist ein wenig lang. Nachteil: man muss mehr lesen.

    Dafür ist der typedef Name ein Name den man lernen muss. Nachteil: man muss mehr Namen im Kopf haben oder dauernd nachdenken/nachgucken was sich hinter dem Namen verbirgt.

    Davon abgesehen sehe ich das aber gleich wie du. 🙂



  • hustbaer schrieb:

    tntnet schrieb:

    Ein std::vector<MyType>::const_iterator mit einem Typedef zu definieren ist sinnvoll, da der voll qualifizierte Bezeichner doch unübersichtlich und schwer zu erfassen ist.

    Das is so ne Sache...

    Der ausgeschriebene Typ ist ein wenig lang. Nachteil: man muss mehr lesen.

    Dafür ist der typedef Name ein Name den man lernen muss. Nachteil: man muss mehr Namen im Kopf haben oder dauernd nachdenken/nachgucken was sich hinter dem Namen verbirgt.

    Davon abgesehen sehe ich das aber gleich wie du. 🙂

    Es ist das beste Beispiel, dass der Motivation die Lesbarkeit und nicht die Tipparbeit sein sollte. Wenn der typedef hilft, den Code lesbarer zu machen, ist er fein. Irritiert er nur, dann sollte man es lassen. Und zwar völlig egal, ob man mehr oder weniger Tippen muss.

    Da ist häufig der auto-Typ sehr praktisch. Nämlich dann, wenn der konkrete Typ der Variablen nicht wirklich relevant ist, um den Code zu verstehen.



  • tntnet schrieb:

    Es ist das beste Beispiel, dass der Motivation die Lesbarkeit und nicht die Tipparbeit sein sollte.

    Exakt.
    Tipparbeit ist so gut wie nie ein Argument dass beim Programmieren zählen darf.

    Um Tipparbeit zu sparen haben wir mächtige Tools die uns Autovervollständigung, Vorlagen, etc. ermöglichen. Wenn man aber überlegt: soll ich den Code so oder so schreiben, dann darf nie die Tipparbeit ein Argument sein.

    Man muss auch bedenken: wieviel Prozent der Zeit verbringt man mit reinem Tippen? 10%? 5%? weniger?



  • Finnegan schrieb:

    Pointer-Dereferenzierung

    Man kann das selbe auch ohne Pointer-Dereferenzierung machen, man muss dazu nur sizeof() und alignof() kennen. 😉
    Is aber - wenn man sich die nötigen Helper-Templates selbst schreiben muss - a bisserl a Aufwand.

    Finnegan schrieb:

    Irgendwann hatte ich dann genug davon und mich für die PIMPL-Isolationshaft entschieden :D.
    Ich gebe allerdings zu, dass ein #define NOMINMAX (und andere) gefolgt von einer #undef -Orgie wahrscheinlich effizienter sind - das kann allerdings andere Nebenwirkungen haben, und Windows-Funktionen werden meist nicht so kritisch eingesetzt,
    dass die zusätzliche Dereferenzierung wirklich einen Unterschied macht.

    Also #include-creep ist schon ne krasse Sache.
    Ich seh das hier bei unseren Projekten, die quasi PIMPL-frei entwickelt wurden.

    Mit windows.h kommt man noch klar, auch wenns immer wieder nervt. Wobei 100% PIMPL-frei sind wir auch nicht. Manche thirdparty Libs vertragen sich einfach nicht mit dieser oder jener anderen Header, und dann muss man irgendwas machen - was dann meist PIMPLn heisst.

    Was aber wirklich nervt ist eben der unglaubliche #include-creep der sich so ansammelt. Du willst eigentlich nur auf irgend eine Helper-Klasse zugreifen, und auf einmal hast du 50 Boost Headers, 10 Crypto++ Headers, noch etliche Xerces Headers und fast das ganze Windows SDK reingezogen. Die Build-Zeiten sehen dann entsprechend aus. Und Precompiled-Headers helfen da auch nur sehr bedingt. Wobei die Zeit für nen kompletten Rebuild nichtmal das schlimmste ist. Viel schlimmer ist es mMn. dass inkrementelle Builds dadurch oft unglaublich langsam werden.

    Also so verkehrt finde ich PIMPL nicht.



  • hustbaer schrieb:

    Was aber wirklich nervt ist eben der unglaubliche #include-creep der sich so ansammelt. Du willst eigentlich nur auf irgend eine Helper-Klasse zugreifen, und auf einmal hast du 50 Boost Headers, 10 Crypto++ Headers, noch etliche Xerces Headers und fast das ganze Windows SDK reingezogen. Die Build-Zeiten sehen dann entsprechend aus. Und Precompiled-Headers helfen da auch nur sehr bedingt.

    Ich freue mich schon auf den Zeitpunkt, wenn wir über diesen altmodischen Quark nur noch lachen können und einfach schreiben:

    import std.io;
       import boost.super_cool;
       import windows.cant_do_it_without_it;
    

    ... und die Datei dann genau so schnell gebaut wird wie ein "Hallo, Welt"-Programm 😃

    Finnegan (Modules-Fan, auch wenns ein bissl wie Java aussieht)



  • Amen.



  • Jopp. Wobei ich nicht damit rechne dass das in diesem Jahrzehnt noch kommt.


  • Mod

    hustbaer schrieb:

    Jopp. Wobei ich nicht damit rechne dass das in diesem Jahrzehnt noch kommt.

    😕 Wie kommste darauf?



  • hustbaer schrieb:

    Manche thirdparty Libs vertragen sich einfach nicht mit dieser oder jener anderen Header

    Jo, zum Beispiel weil die thirdparty Libs alle die selbe andere thirdparty Lib benutzen aber in verschiedenen Versionen.
    Da kriegste aber auch ohne Header Ärger, z.B. wenn die Oracle-CLient-Lib-DLL Funktionen von Kerberos exportiert.

    hustbaer schrieb:

    Was aber wirklich nervt ist eben der unglaubliche #include-creep der sich so ansammelt. Du willst eigentlich nur auf irgend eine Helper-Klasse zugreifen, und auf einmal hast du 50 Boost Headers, 10 Crypto++ Headers, noch etliche Xerces Headers und fast das ganze Windows SDK reingezogen. Die Build-Zeiten sehen dann entsprechend aus.

    Kann ich nicht nachvollziehen.


Anmelden zum Antworten