Ersatz für finally



  • lolz schrieb:

    hustbaer schrieb:

    Schwer zu lesen würde ich nicht sagen, aber wenn man mal nicht genau aufpasst macht man schnell mal was in der falschen Reihenfolge. Und dann gibts unerwünschtes in bestimmten Spezialfällen, nämlich wenn genau dort eine Exception fliegt wo man nicht daran gedacht hat.

    Ich habe die Erfahrung gemacht, dass man das "in der falschen Reihenfolge"-Problem meist dadurch hat, dass verwendete Bibliotheken kein RAII benutzen oder sonstige Technologien wie z.B. Smart-Ptr.

    Also ich bin schon öfter über sowas drübergestolpert. Nicht jeden Tag, aber doch ab und an mal. Mal in meinem eigenen Code, mal in fremdem Code. Mal liegt es wirklich nur daran dass jmd. zu faul war (oder nicht daran gedacht hat) auf unterster Ebene bereits RAII Klassen einzuziehen, mal liegt es aber auch daran dass man gewisse Invarianten halten muss die u.U. garnichts mit Resourcen zu tun haben. Verändert man dann mehrere Member kann es leicht passieren dass man ein "might throw" irgendwo übersieht. Oft denkt man sich "der blöde Getter schmeisst eh nix". Krachbumm, angeschissen, der schmeisst halt doch, weil intern irgendwo nen std::string oder sonstwas verwendet wird. Ganz toll auch Dinge wie boost::lexical_cast - sieht so harmlos aus, kann aber Gott und die Welt werfen (std::bad_alloc sowieso immer und alles mögliche was im "operator <<" bzw. "operator >>" noch so fliegen kann).

    Manchmal ist es auch nicht bloss "in der falschen Reihenfolge" sondern eine Spur mehr - man muss (zusätzliche) temporäre Variablen zu Hilfe nehmen oder im schlimmsten Fall selbst zusätzliche Guards für irgendwas schreiben.



  • BerndD schrieb:

    Die Zeile

    CAqqLock lock(cs);
    

    könnte auch ein vergessene lokale Variable sein oder ein Makro oder sonstwas. Natürlich lässt sich das schnell klären. Das Problem ist nur, wenn es nicht der eigene Quelltext ist, wird es unzählige Stellen geben die "nur mal schnell abzuklären" sind.

    Wenn du nur einen kleinen Code betrachtest: ja.
    wenn du aber das ganze Programm betrachtest, dann ist ein "Lock lock(cs);" ziemlich eindeutig.

    Vieles was du auf RAII bezogen hast, stimmt natürlich. Aber auch ein try/catch/finally ist nicht perfekt. Denn wo du in C++ ein "Lock lock(cs)" siehst, sieht man in Java "lock(cs);" und "finally{unlock(cs);}". Hier hat man ähnliche Probleme wie in C++.

    Ich sage nicht dass eins besser ist, ich sage nur deine Sichtweise ist etwas eingeschränkt.



  • Shade Of Mine schrieb:

    Vieles was du auf RAII bezogen hast, stimmt natürlich. Aber auch ein try/catch/finally ist nicht perfekt. Denn wo du in C++ ein "Lock lock(cs)" siehst, sieht man in Java "lock(cs);" und "finally{unlock(cs);}". Hier hat man ähnliche Probleme wie in C++.

    Hach, wieso auch der Vergleich mit Java?

    VB:

    SyncLock MeineVariable
        ' … Let's see action
    End SyncLock
    

    C#:

    lock(MeineVariable) {
        // … let's see people.
    }
    

    Aber zugegeben, das ist ein Ausnahmefall. Das IDisposable-Codemuster ist eine Katastrophe und illustiert IMHO gut, dass die Nachteile der nichtdeterministischen Ressourcenverwaltung deren Vorteile überwiegen.



  • du kannst in c++ aber auch

    void foo() {
      Lock lock(cs); {
        bla();
      }
    }
    

    schreiben wenn du den Block betonen willst...



  • Shade Of Mine schrieb:

    du kannst in c++ aber auch

    void foo() {
      Lock lock(cs); {
        bla();
      }
    }
    

    schreiben wenn du den Block betonen willst...

    Ja, aber das ist etwas anderes (man beachte den Scope des Lock). Ist aber alles irrelevant, der Unterschied ist, dass das eine eben durch ein Sprachkonstrukt gegeben ist und daher jede weitere Diskussion um den Zweck entfällt, während das andere eben eine Konvention (bzw. ein Idiom ist) und damit unter die von Bernd genannte Kritik fällt.

    Ich will aber auch gar nicht behaupten, dass die Variante von VB/C# unbedingt besser ist. Aber sie hat definitiv nicht das von Dir aufgezeigte Problem, welches man in Java mit dem Finally-Block hat (da eben auch hier ein passendes Sprachkonstrukt für ein Lock fehlt).



  • BerndD schrieb:

    ...
    Ohne es zu wollen sprichst du gleich die zwei Hauptgründe an, warum es schwerer zu lesen ist als ein try/finally. ...

    Und Du glaubst nicht, dass es sich hier eher um "persönliche Präferenzen" handelt ?
    Irgendwie erinnert mich das an Diskussionen aus meinem Studium: Als Physiker war ich froh, wenn ich mit einer Gleichung ein ganzes System/Modell im Griff hatte. In dieser "Formel" (Maxwell, Schrödinger, Lagrange, ....) lag "das Wissen", das man auf (fast) alle Anwendungsfälle anwenden konnte. Man konnte verschiedene Aspekte und Zusammenhänge ableiten, entwickeln, neu entdecken, ...
    Das fand ich "übersichtlich".
    Ingenieure (oder erst Recht: Mediziner) hingegen fanden das meistens ganz anders ("Ja, aber wenn ich das für diesen Fall brauche, dann muss ich da ja erst umformen !") - die freuten sich, wenn sie 85 verschiedene "Formeln" (allesamt Ableitungen "meiner" einen Gleichung) auswendig und anzuwenden lernen konnten.
    Das fanden sie "übersichtlich".

    Ist für mich komplett wertfrei - und definitiv nicht zu klären, wer jetzt "Recht" hat.

    BerndD schrieb:

    ...

    Simon2 schrieb:

    P.P.S.: Wie ist das eigentlich mit "finally": Wird das auch ausgeführt, wenn die die exception nirgends gefangen wird ? Ist bei RAII ja nicht unbedingt so...

    Der Delphi Compiler legt am Anfang des try Block eine pseudo Rücksprung Adresse auf den Stack...

    Hmmm ... ich habe mal gelesen, dass C++-Compiler beim "kompletten Durchrauschen einer exception" auf's stack-unwinding verzichten, um bei Programmende noch denselben Programmzustand (Stack etc.) zu haben, wie beim Auftreten der exception ... das wäre natürlich bei so eine finally(), das dann trotzdem noch greift (am besten noch mehrer geschachtelte), nicht so.

    Nunja ... ich habe bislang noch keine Bedarf an "finally" und finde (!!!) RAII immer übersichtlicher und eleganter.

    Gruß,

    Simon2.



  • Shade Of Mine schrieb:

    du kannst in c++ aber auch

    void foo() {
      Lock lock(cs); {
        bla();
      }
    }
    

    schreiben wenn du den Block betonen willst...

    😮 😮
    Oha - DAS würde ich nun gar nicht machen, weil z.B.

    void foo() {
      Lock lock(cs); {
        bla1();
      }
      bla2();
    }
    

    ...etwas ganz anderes macht als durch "den Block" suggeriert.

    Gruß,

    Simon2.



  • Simon2 schrieb:

    Shade Of Mine schrieb:

    du kannst in c++ aber auch

    void foo() {
      Lock lock(cs); {
        bla();
      }
    }
    

    schreiben wenn du den Block betonen willst...

    😮 😮
    Oha - DAS würde ich nun gar nicht machen, weil z.B.

    void foo() {
      Lock lock(cs); {
        bla1();
      }
      bla2();
    }
    

    besser so:

    void foo() 
    {
      bla0();
      // der block ist gelockt 
      { 
        Lock lock(cs); 
        bla1();
      }
      // ab hier ist wieder 'unlocked'
      bla2();
    }
    

    und zum 'betonen' macht man besser die geschweifen klammern in eine neue zeile, sonst betont man nicht viel.
    🙂



  • Undertaker schrieb:

    ...
    besser so:
    ...

    Ich glaube, Du hast nicht verstanden, worauf Shade hinauswollte..... 😃
    Hast Du eigentlich eine Forumstrigger auf den Begriff "Java" ?

    Gruß,

    Simon2.



  • Simon2 schrieb:

    Ich glaube, Du hast nicht verstanden, worauf Shade hinauswollte..... 😃

    mit geschweiften klammern die 'reichweite' des locks andeuten, oder nicht?

    Simon2 schrieb:

    Hast Du eigentlich eine Forumstrigger auf den Begriff "Java" ?

    wo ist hier java?
    🙂



  • Undertaker schrieb:

    ...
    mit geschweiften klammern die 'reichweite' des locks andeuten, oder nicht?
    ...

    Naja, aber Dein Code wurde (mit dieser Intention) doch bereits im 2. Posting von CStoll gepostet... deswegen vermutete ich, Du wolltest noch ein wenig mehr/anderes.

    Undertaker schrieb:

    ...
    wo ist hier java?
    🙂

    5 Posts über Deinem ersten:

    Konrad Rudolph schrieb:

    ...
    Hach, wieso auch der Vergleich mit Java?...

    (mal ganz abgesehen davon, dass das letzte Wort aus dem Threadtitel wohl dieser Sprachen entnommen worden sein dürfte) 😃

    Gruß,

    Simon2.



  • Simon2 schrieb:

    Undertaker schrieb:

    ...
    mit geschweiften klammern die 'reichweite' des locks andeuten, oder nicht?
    ...

    Naja, aber Dein Code wurde (mit dieser Intention) doch bereits im 2. Posting von CStoll gepostet... deswegen vermutete ich, Du wolltest noch ein wenig mehr/anderes.

    nö, das war nur als antwort auf dein posting gedacht. was auf der vorherigen seite stand, hab' ich gar nicht gelesen...

    Undertaker schrieb:

    ...
    wo ist hier java?
    🙂

    ...

    Simon2 schrieb:

    (mal ganz abgesehen davon, dass das letzte Wort aus dem Threadtitel wohl dieser Sprachen entnommen worden sein dürfte) 😃

    ich dachte bei 'finally' mehr an diese microsoft extensions __try, __except, __finally, weniger an Java.
    --> http://msdn2.microsoft.com/en-us/library/s58ftw19(VS.71).aspx



  • Ach so.

    Undertaker schrieb:

    ..
    ich dachte bei 'finally' mehr an diese microsoft extensions __try, __except, __finally, weniger an Java.
    --> http://msdn2.microsoft.com/en-us/library/s58ftw19(VS.71).aspx

    Ist ja auch naheliegender !! 👍
    (Da Du allerdings nicht für das Verfassen des Threadtitels verantwortlich bist, ist nicht ganz ausschlaggebend - und von mir auch nicht gemeint - , was Du damit assoziierst).

    Gruß,

    Simon2.



  • Dann hätte man auch __finaly schreiben müssen. 🙄 War aber nirgends zu sehen.



  • Artchi schrieb:

    Dann hätte man auch __finaly schreiben müssen.

    muss man nicht. das delphi-zeugs Try/Except/Finally ist fast das selbe wie der m$-kram und wird wahrscheinlich eine 1:1 umsetzung sein, um das windows-eingebaute SEH zu nutzen (z.b. so fiese sachen wie division durch 0 abzufangen)...
    🙂



  • Konrad Rudolph schrieb:

    .. Ist aber alles irrelevant, der Unterschied ist, dass das eine eben durch ein Sprachkonstrukt gegeben ist und daher jede weitere Diskussion um den Zweck entfällt, während das andere eben eine Konvention (bzw. ein Idiom ist) und damit unter die von Bernd genannte Kritik fällt.

    Genau das ist auch mein Standpunkt.

    Simon2 schrieb:

    BerndD schrieb:

    ...
    Ohne es zu wollen sprichst du gleich die zwei Hauptgründe an, warum es schwerer zu lesen ist als ein try/finally. ...

    Und Du glaubst nicht, dass es sich hier eher um "persönliche Präferenzen" handelt ?

    Nein, weil es in meiner Argumentation nicht darum ging welche Sprache die bessere ist. Solche Diskussionen halte ich für Sinnfrei. Daher auch der Hinweis mit den "Glaubenskrieg".
    Hätte ich die Wahl zwischen try/finally oder RAII würde ich mich sicher für RAII entscheiden. Mir wäre aber trotzdem bewusst, das mein Quelltext für Personen, die das Idiom nicht kennen, schwerer zu lesen wäre. Daher auch der begeisterte Ausruf: "Elegant und schwer lesbar. Eine echte C++ Lösung!"

    Simon2 schrieb:

    Irgendwie erinnert mich das an Diskussionen aus meinem Studium: ...

    Ein schönes Beispiel. Es deckt sich auch mit meinen Erfahrungen. Nur wenige Menschen haben es geschafft den hohen Abstraktionsgrad zu erreichen, den du als Physiker erreicht hast. Nur mit diesem kannst du über die formale Sprache "Formel" kommunizieren. Alle anderen sind ausgesperrt. Es würde mir aber keine Sorgen bereiten von einen Chirurgen operiert zu werden, der die Maxwellsche Gleichung nicht anwenden kann. Mehr Sorge ich mich, des es Menschen gibt die zwar einen hohen Grad an Erkenntnis erlagt haben, es aber nicht mehr Schaffen dieses Wissen in ein interdisziplinäre Anwendergruppe einzubringen, weil sie nicht mehr allgemein verständlich kommunizieren können (Bitte das jetzt nicht auf dich beziehen).

    ...Ist für mich komplett wertfrei - und definitiv nicht zu klären, wer jetzt "Recht" hat.

    Das wollen wir doch auch nicht klären! Wir schauen von verschiedenen Standpunkten auf die selbe Sache. Und ich habe ein "Schwätzchen" darüber gemacht, was ich von meinem Standpunkt aus sehe. Ich hoffe es war nicht zu langweilig für euch.

    Gruß,
    Bernd



  • BerndD schrieb:

    Und ich habe ein "Schwätzchen" darüber gemacht, was ich von meinem Standpunkt aus sehe. Ich hoffe es war nicht zu langweilig für euch.

    Nö, auf keinen Fall. Ich finde diese Diskussionen generell bereichernd, weil man sich dadurch häufig zum ersten Mal über gewisse Sachverhalte Gedanken macht und diese hinterfragt.



  • BerndD schrieb:

    ...

    Simon2 schrieb:

    BerndD schrieb:

    ...
    Ohne es zu wollen sprichst du gleich die zwei Hauptgründe an, warum es schwerer zu lesen ist als ein try/finally. ...

    Und Du glaubst nicht, dass es sich hier eher um "persönliche Präferenzen" handelt ?

    Nein, weil es in meiner Argumentation nicht darum ging welche Sprache die bessere ist. ...

    Da das Argument gar nichts mit dem zu tun hat, was ich sagen wollte, liegt hier wohl ein Missverständnis vor. Meine Aussage war: "Deine Einschätzung 'ist schwerer zu lesen als' ist IMO zu stark mit persönlichen Präferenzen verknüpft als dass man sie in der Allgemeinheit stehen lassen kann. Und das liegt gar nicht mal am Thema ("finally/RAI"), sondern an der Kategorie "lesbar" ..."

    BerndD schrieb:

    ...
    Mehr Sorge ich mich, des es Menschen gibt die zwar einen hohen Grad an Erkenntnis erlagt haben, es aber nicht mehr Schaffen dieses Wissen in ein interdisziplinäre Anwendergruppe einzubringen, weil sie nicht mehr allgemein verständlich kommunizieren können (Bitte das jetzt nicht auf dich beziehen). ...

    Das ist einfach das übliche Problem menschlicher Kommunikation: Man steckt in seinem eigenen Kopf und kann sich nur bruchstückhaft in den Anderen hineinversetzen ... einige mehr, andere weniger. Und das gilt "für beide Seiten": Wer etwas als selbstverständlich lesbar empfindet, kann nicht verstehen, dass jemand anderes (ohne "dümmer" zu sein) das nicht tut ... und auch wer etwas "natürlich" total unlesbar empfindet, tut sich mit der Vorstellung schwer, dass Andere das ebenso "natürlich" lesbar finden (ohne "abgefahrene Freaks" zu sein).

    BerndD schrieb:

    ...Ist für mich komplett wertfrei - und definitiv nicht zu klären, wer jetzt "Recht" hat.

    Das wollen wir doch auch nicht klären!

    Wieder ein Missverständnis: Ich habe das nicht erwähnt, um Dich damit zu belehren/korrigieren/... , sondern nur, damit Du meine vorherigen Thesen gerade NICHT missverstehst (als wertend) - was ich damit geschickt ad absurdum geführt habe. 😉

    Gruß,

    Simon2.


  • Administrator

    BerndD schrieb:

    Konrad Rudolph schrieb:

    BerndD schrieb:

    Elegant und schwer lesbar.

    Nicht schwer lesbar sondern ein Idiom, das man sich aneignen muss. Wenn man RAII verstanden hat, ist diese Lösung sehr verständlich und leuchtet auf den ersten Blick ein.

    Ich meinte weniger "Schwer lesbar, weil nicht Wissen wie es funktioniert", sondern "Schwer lesbar, weil Implementationsabhängig".
    Die Zeile

    CAqqLock lock(cs);
    

    könnte auch ein vergessene lokale Variable sein oder ein Makro oder sonstwas. Natürlich lässt sich das schnell klären. Das Problem ist nur, wenn es nicht der eigene Quelltext ist, wird es unzählige Stellen geben die "nur mal schnell abzuklären" sind.

    Als ich das las, dachte ich im ersten Moment: "hmmm, hat er wohl recht. Vor allem, wenn man verschiedene Locks benötigt. Das sind immer wieder neue Klassen und man muss womöglich immer wieder schnell nachschauen was das ist".

    Aber hatte dann eine kleine Idee und sie umgesetzt. Ich staune selber, dass es funktioniert ^^

    #include <iostream>
    #include "conio.h"
    
    template<class C>
    class CLock
    {
    	C& m_Class;
    	void (C::*m_funcConstruct)();
    	void (C::*m_funcDestruct)();
    
    public:
    	CLock(C& Class, void (C::*funcConstruct)(), void (C::*funcDestruct)()) 
    		: m_Class(Class)
    		, m_funcConstruct(funcConstruct)
    		, m_funcDestruct(funcDestruct)
    	{
    		if(m_funcConstruct) (m_Class.*m_funcConstruct)();
    	}
    
    	~CLock()
    	{
    		if(m_funcDestruct) (m_Class.*m_funcDestruct)();
    	}
    };
    
    // Testen ob es funktioner:
    
    class CTest
    {
    public:
    	void start() { std::cout << "Start" << std::endl; };
    	void end() { std::cout << "End" << std::endl; };
    };
    
    int main()
    {
    	{
    		CTest t;
    		CLock<CTest> Lock(t, &CTest::start, &CTest::end);
    
    		_getch();
    	}
    
    	_getch();
    
        return 0;
    }
    

    Daher, du siehst diese Klasse einmal und weisst immer was sie macht. Kommt doch beinahe an das finally heran, eine Formel? Dafür hat man den Spass es selber zu machen *g*

    Grüssli

    PS: Die Klasse ist sicherlich noch Verbesserungswürdig, ist nur so "schnell" dahingeklatscht 😉



  • Dravere schrieb:

    Aber hatte dann eine kleine Idee und sie umgesetzt. Ich staune selber, dass es funktioniert ^^
    *snip*

    Dieses Idiom (bzw. Muster) trägt sogar einen Namen, habe vergessen, welchen aber ich glaube, es war „delegated responsibility“.


Anmelden zum Antworten