Defensive Programmierung



  • Das hat jetzt aber nix mit meinem <es wäre schön ...></> zu tun, oder? Von statischem Checking seh ich da nix, nur eine Technik, mit der man u.a. DBC-Konstrukte bauen kann.



  • @Bashar:
    Doch ... nur am Begriff 'static' stoß ich mich ein bischen.

    Trennung von Komponenten und Aspekten
    Ein wichtiger Begriff im AOP-Konzept ist das so genannte Code Tangling. Er bezeichnet die ‘Verschmutzung’ des funktionalen Codes durch den der verschiedenen Aspekte, die der funktionale Code zusätzlich aufnehmen muss, damit bestimmte Randbedingungen erfüllt sind. Für SimpleMessageQueue ist jetzt also das Code-Tangling geringer geworden, der Aspekt Thread-Sicherheit macht circa 40 Prozent der endgültigen Implementierung aus.

    AOP soll den Programmierer darin unterstützen, Komponenten und Aspekte sauber voneinander zu trennen. Dazu stellt es Mechanismen zur Verfügung, die einerseits das Auffinden von Aspekten und andererseits das Zusammenfügen aller Teile zum Gesamtsystem ermöglichen (siehe [5]).

    Ein Aspekt kann somit aus zwei Blickwinkeln beschrieben werden. Einerseits verkörpert er eine Anforderung an ein System. Andererseits stellt er ein Programmkonstrukt dar, das die Anforderung kapselt - etwa eine Klasse in Java.

    Dadurch dass Aspekte bestimmte Anforderungen in eigene Module auslagern, lässt sich im Gesamtsystem eine stärkere Trennung bezüglich der Anforderungen von Design und Implementierung durchhalten. Dabei werden Modul-, Objekt- und Komponentengrenzen in gewisser Hinsicht aufgehoben, da Aspekte auf Objekte zugreifen können, ohne sich dabei auf deren öffentliche Schnittstelle beschränken zu müssen. Aber eigentlich werden diese Grenzen nicht wirklich verletzt, da der gleiche Aspekt, der auf mehrere Objekte wirkt, diese unabhängig voneinander erweitert und er integraler Bestandteil jedes der betroffenen Objekte wird. Hier gibt es gewisse Ähnlichkeiten von Aspekten und Bibliotheken.

    Beispiele für Aspekte sind:

    Tracing/Logging und Monitoring/Diagnose/Profiling
    Fehlerbehandlung und Fehlertoleranz
    Synchronisation/Thread-Sicherheit
    Caching-Strategien
    Resource-Sharing
    Echtzeit
    History
    Optimierungen
    Objekt-Interaktion
    Transaktionen
    Sicherheit
    Konfiguration
    Test
    Verteilbarkeit und Fernaufrufe
    einheitliches Look & Feel von Benutzerschnittstellen

    http://www.heise.de/ix/artikel/2001/08/143/03.shtml



  • Anscheinend drück ich mich unklar aus: Mit statischem Checking mein ich, dass der Compiler *beweist* dass eine Assertion gültig ist (ich glaube SPARK kann sowas). Das Wort statisch ist die Essenz des ganzen, wenn du dich daran störst, bist du hinter einem ganz anderen Problem her als ich.



  • @Bashar:
    Das ist für mich wieder ein Regressionstest ... wir drehen uns im Kreis...
    Compiler mit Regressionstest?! 😕
    Wäre aber mal eine Erfindung. 🙂



  • Mir scheint ich sollte mal in Erfahrung bringen was ein Regressionstest genau ist bevor ich hier weiterposte 😉 schönes Wochenende dann ...



  • Auch so...
    Hellau!! 😃



  • Original erstellt von Prof84:
    Auch so...
    Hellau!! 😃

    *Arghh* 😡



  • ich bin der meinung dass foo keine chanze hat irgendwas zu ändern. Wenn jetzt ein NULL Zeiger übergeben wird, was kann foo machen? Exception werfen, OK.

    Aber bar() kann viel mehr machen. bar() weiss dass die Datei "baz" sich nicht öffnen hat lassen. Also sollte bar() vielleicht schaun ob genug rechte da sind oder so - zumindest kann bar() einen sinnvollen Fehler ausgeben.

    Das Problem bei foo() ist nämlich: es hilft nichts wenn foo() meldet: "man hat mir einen ungültigen Pointer übergeben". Dann muss ich nämlich suchen WO foo() aufgerufen wurde. OK, das geht ja mit debuggern recht gut - allerdings was machen wir wenn der Fehler nicht reproduzierbar ist? Dann wissen wir nur, dass foo() uU mit einem 0-Zeiger aufgerufen werden kann - Notlösung (was leider bei uns dann gemacht wird):
    if(!f) return;
    aber ist das das wahre?



  • Original erstellt von Shade Of Mine:
    **Exception werfen, OK.
    **

    der sinnvollste ort wo sie gecatcht werden sollte wäre in bar, alles ander kommt ein assert ähnlich, was sonnst sollen die oben da machen wenn sie von irgend wo unten so eine exception bekommen?

    Original erstellt von Shade Of Mine:
    Notlösung (was leider bei uns dann gemacht wird):
    if(!f) return;
    aber ist das das wahre?

    ist das nicht auch ein fehler im weitern programm verlauf?



  • ich bin der meinung dass foo keine chanze hat irgendwas zu ändern. Wenn jetzt ein NULL Zeiger übergeben wird, was kann foo machen? Exception werfen, OK.

    Naja, bei der defensiven Programmierung, wird foo wohl nie in die Situation kommen einen NULL Zeiger zu erhalten, deswegen ist ja defensive Programmierung quatsch.

    🙂

    Aber ich muss dir recht geben, Fehler fängt man am besten an der Stelle ab, an de man dem User eine Vernünftige Fehlermeldung geben kann und ihm danach ein stabiles System überlassen kann.



  • das Beispiel war wohl zu abstrakt, geb ich zu. foo müßte ein boolsches Ergebnis haben und bei Fehlern nach oben propagieren, wenn es keine Exception wirft. Das Problem ist, dass ich momentan mit C arbeite (Legacy-Code), also keine Exceptions zur Verfügung habe.

    Unter Umständen kann sich das ändern, aber dazu muß ich mich erst durchringen.



  • man kann auch unter C Exceptions simulieren, ist zwar nicht so toll wie in C++, aber hier ist mal ein kleiner denkanstoß

    #include <setjmp.h>
    #include <stdio.h>
    #include <stdlib.h>
    
    struct exception_t
    {
      int no;
      jmp_buf buf;
    };
    
    struct exception_t NOMEMORY;
    
    void init_exceptions(void)
    {
      NOMEMORY.no=1;
    }
    
    inline void throw(struct exception_t exception)
    {
      longjmp(exception.buf,exception.no);
    }
    
    #define catch(exception,dofunc,doexception) \
    { \
      int ret=setjmp(exception.buf); \
      if(ret==0) \
        dofunc \
      else if(ret==exception.no) \
        doexception \
    }
    
    void *mymalloc(size_t n)
    {
      void *ptr=malloc(n);
      if(!ptr)
        throw(NOMEMORY);
      return ptr;
    }
    
    void foo(void)
    {
      free(mymalloc(1000000000000000u));
    }
    
    int main(void)
    {
      init_exceptions();
      catch(NOMEMORY,
      {
        foo();
      },
      {
        fprintf(stderr,"nicht genug speicher!\n");
        exit(1);
      });
      return 0;
    }
    


  • das Stack-Unwindig von longjmp ist nicht ganz so toll, da es keine Destruktoren (die es in C ohnehin nicht gibt) aufruft, dh sobald ich Resourcen anfordere, die ich explizit freigeben muß, geht das in die Hose.



  • ja, dass ist natürlich ein Problem. Aber das kann einem in C++ auch passieren (was nicht heissen soll, dass die Methode jetzt gut ist mit longjmp ;))



  • ja theoretisch, aber das Verhältnis von dynamischen und automatischen Objekten ist in C++ ein ganz anderes als in C. In C passiert alles was über primitive Datentypen und Mini-structs hinausgeht dynamisch, während sowas in C++ in Klassen mit auto-Semantik verpackt ist. Nimm doch nur Stringhandling als Beispiel.

    [ Dieser Beitrag wurde am 01.03.2003 um 16:51 Uhr von Bashar editiert. ]


Anmelden zum Antworten