![]() |
AW: Verträge für Delphi / Design by Contract
Was die Laufzeit Auswertung angeht, kann man das über AOP machen.
|
AW: Verträge für Delphi / Design by Contract
für ein Vorbedingungs- Nachbedingungs- Zwischenbedingungs Sonstiges
Kontroll-Konstrukt kann man schön methodenlokale Prozeduren/ funktionen nutzen( die nat. ggf andere Methoden aufrufen). Je nach Lage der methodenlokalen Variablen zur o.a. Prozedur/Fkt kann man dann auf diese Variablen und die Parameter wie gewünscht zugreifen oder aber aus dem Zugriff raushalten. Mal so auf die Schnelle:
Delphi-Quellcode:
type
TMyCheckSituation = (sVB, sSit1, sNB ); procedure TForm3.Mach(aInt: integer); var TestMe: integer; procedure Chk( const MySituation: TMySituation); begin case MySituation of sVB: if (aInt<8) and ( TestMe<0) then // Testfehler!: // irgendwie Fehlerbedingung händeln, z.B: except. raise Exception.Create('Loud Cry'); sSit1: ;// Check für Sit.1 sNB: ;// Nachbedingungsckeck; end; DoMyGeneralTest; end; var DontTestMe: integer; begin Chk(sVB); // Situationstest Vorbedingung DontTestMe := 1; MachWas; TestMe := DontTestMe; {$REGION 'InnerCheck SaubereMitte'} Chk(sSit1); // Situationstest Situation 1 {$ENDREGION} MachNochWas; Chk(sNB); // NachBedingung end; |
AW: Verträge für Delphi / Design by Contract
Nur so eine Idee, die mir gerade kam, aber vielleicht könnte man auch records dafür missbrauchen.
Z.B.:
Delphi-Quellcode:
Keine Ahnung, ob Delphi das Konstrukt überhaupt zulässt... ich hatte mit dem Implicit-Operator unter Delphi 2006 schon bei harmloseren Sachen Probleme, aber bei 2006 waren überladene record-Operatoren generell buggy.
type
EContractViolation = class(Exception) end; TObjectNotNil = record private FObj: TObject; public operator Implicit(const Obj: TObject): TObjectNotNil; operator Implicit(const Obj: TObjectNotNil): TObject; end; operator TObjectNotNil.Implicit(const Obj: TObject): TObjectNotNil; begin if not Assigned(Obj) then raise EContractViolation.Create("Reference must not be nil"); Result.FObj := Obj; end; operator TObjectNotNil.Implicit(const Obj: TObjectNotNil): TObject; begin Result := Obj.FObj; end; procedure DoSomethingWithObject(Obj: TObjectNotNil); begin Obj.{...} end; DoSomethingWithObject(nil); // => EContractViolation Und natürlich ist das so, wie es hier steht, viel zu aufgebläht... aber vielleicht könnte man ja irgendwie einen Preprocessor schreiben, der den Code vor der Kompilierung generiert, oder vielleicht kann man mit Generics noch was rausholen. Wahrscheinlich ist das alles nicht wirklich praktikabel, aber ich wollte die Idee gerade mal niederschreiben... |
AW: Verträge für Delphi / Design by Contract
Zitat:
Das funktioniert so aber auch schon mit Delphi 2006 würde ich behaupten, auch wenn ich das gerade nicht testen kann... Ich habe dort schon relativ viel mit Klassenoperatoren gemacht und hatte damit keine Probleme. |
AW: Verträge für Delphi / Design by Contract
Das geht auch mit einem generischen Record, so wie
![]() Kleiner Unterschied bei dieser Lösung allerdings ist, dass im Falle von nil die Exception vor dem Aufruf und nicht danach bzw innerhalb der aufgerufenen Methode geraised wird. |
AW: Verträge für Delphi / Design by Contract
Solche Lösung sind zwar gut gegen Nullpointer, biete aber keine statische Analysefähigkeit.
Das ist es, was die Design-by-Contract so wertvoll macht. Anfangs- und Endzustände sowie Invarianten checken kann man zwar manuell machen. Aber schon mit dem (erzwungenen) Vererbungen der "Contracts" wird ohne Compiler-Unterstützung kniffelig bis unmöglich. Es ist wie mit der Typen: Wenn es nicht erzwungen wird, ist nicht so viel Wert. Das Argument mit dem Halteproblem kann ich nicht nachvollziehen. Abgesehen von dem begrenzten Speicher sollte es problemlos möglich sein, eine Turingmaschine zu realisieren. Schließlich bieten die Contracts keine Aussage über die Laufzeit. |
AW: Verträge für Delphi / Design by Contract
Zitat:
|
AW: Verträge für Delphi / Design by Contract
Zitat:
Aber ich glaube, mir ist eben des Halteproblemargument aufgegangen: Es ist nicht aufgrund des Halteproblems nicht möglich, herauszubekommen, ob zwei Prozeduren (~> Turingmaschinen) das selbe Ergebnis liefern. Also müsst der Programmierer im Zweifelsfall vor dem Aufruf explizit auf die gleiche Bedingung prüfen, die in dem Contract spezifiziert ist. Das wäre unschön (keine Perfektion). Ich glaube aber, dass wirklich praktisch auftretende Problem ist, dass Contracts nur eine weitere Spezifikationen sind, die unvollständig oder schlicht gänzlich falsch sein können. |
AW: Verträge für Delphi / Design by Contract
Zitat:
|
AW: Verträge für Delphi / Design by Contract
Zitat:
Du hast eine Funktion A die gemäß Contract einen beliebigen Wert zwischen 1 und 10 zurückliefern kann. Du hast eine andere Funktion B, die einen Parameter hat der per Contract nur Werte zwischen 0 und 5 annehmen darf. Wenn Du nun eine Variable aus A füllst und in B reinwirfst, dann kann Dir der Compiler eine Warnung um die Ohren hauen das dieses Ding Deinen Contract verletzt. Du kannst nun entweder * die Fälle von 6-10 mit einer Sonderbehandlung bedienen und nur die Werte bis 5 in B reinwerfen * oder aber sicherstellen das A nur noch Werte zurückgibt die B auch annehmen kann * oder aber dafür sorgen das B auch Werte bis 10 verträgt. Machst Du nichts davon und ignorierst die Warnung einfach, DANN wirst Du möglicherweise zur Laufzeit Probleme bekommen. Es geht ja nicht darum, vollumfänglich zur Compilezeit sicherzustellen das da nie was falsches reingegeben wird. Es geht darum, das Dir der Compiler vorab ausreichend Hinweise gibt wo es eben potentiell zu Contractverletzungen und damit zu möglichen Fehlerquellen kommen kann. So kann man nämlich vorher mögliche Problemfälle analysieren, automatisch testen und muss nicht erst warten bis es draussen irgendwo wegen einer seltsamen Eingabe mal in einem Edge-Case zu einem Fehler kommt. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 22:18 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz