mmofacts.com

Assertions

gepostet vor 17 Jahre, 8 Monate von None
Arbeitet jemand hier mit assertions bzw. hat Erfahrung damit?
Die PHP Entwickler wird das nichts sagen, aber der C++ und Java Fraktion wird es ein Begriff sein.
Hab mir vorgenommen diesmal das Projekt von vorneherein mit assertions zu machen. Damit erhoffe ich mir ne Menge Arbeit zu sparen. In C++ ist es ja soweit üblich ne Debug-Libary mitzuliefern um assertions zu haben. Unter java nutzt es kaum jemand, ist einfach nicht so 100%ig der "java way".
Wäre schön mal Erfahrungen und Beispiele zu dem Thema zu hören. Lohnt es sich damit zu arbeiten?
Für alle die keine Ahnung haben was es ist:
java.sun.com/j2se/1.5.0/docs/guide/language/assert.html
Kurz erklären lässt es sich wohl am Besten so:
man schreibt eine spezielle if-Abfrage in seine Methoden. Die werden im Debug-Modus vom Compiler/Java VM ausgewertet und bei ner if-Abfrage die false ergibt wirft er ne Exception. Damit erkenne ich sofort wenn ich Fehler im Programm (um genau zu sein: in der Vor- oder Nachbedingung) habe ohne den Debuger anwerfen zu müssen und auf Fehlersuche zu gehn.
Im Release-Code werden assertions schlicht und einfach ignoriert und werden automatisch zu "Kommentaren". Keine Rechenzeit wird darauf verschwendet sie auszuwerten. Sie sind programmtechnisch nicht da.
gepostet vor 17 Jahre, 8 Monate von TheUndeadable
In C# nutze ich sie regelmäßig und helfen ungemein beim Entwickeln selbst.
Wobei ich persönlich auch im Release-Build meist Überprüfung im Stile von:
void Funktion ( Object oObject )
{
if ( oObject == null ) throw new ArgumentNullException ("oObject");
}
nutze.
Die Ausnahmen, die dann in den Logs auftreten lassen sich so wesentlich besser auswerten.
gepostet vor 17 Jahre, 8 Monate von Todi42
Ich habe in C++ Massen an asserts verwendet und die sind auch mit der Software ausgeliefert worden. Assert verwendet man typischer Weise dort, wo Invarianten gebrochen werden und es unklar ist, wie es überhaupt zu so einen Zustand kommen konnte, oder es unklar ist, was dem nächst passieren wird. Dann lieber ein kurzes schnelles Ende mit der Möglichkeit, den Fehler zu finden.
Bei C++ gibt es jede Menge Sachen, die undefiniertes Verhalten haben und genau in dieses undefinierte Verhalten möchte man besser nicht rein kommen. Bei Java gibt es so etwas nicht und da sind die Chancen, das man mit eine Exception wieder zurück zu einem Punkt kommt, in dem das Programm wieder einen definierten Zustand hat viel größer.
gepostet vor 17 Jahre, 8 Monate von None
Original von Todi42
Bei Java gibt es so etwas nicht und da sind die Chancen, das man mit eine Exception wieder zurück zu einem Punkt kommt, in dem das Programm wieder einen definierten Zustand hat viel größer.

Gut, bei C++ ist das logisch. In Java findet man natürlich keine Invarianzen, wie oben geschrieben nutzt man es um Vor- und Nachbedingungen zu prüfen. Das bringt aber auch ne Menge Erleichterung (hoffe ich).
Werde mich mal daran versuchen und prüfen wie es in Java anschlägt. Immerhin hab ich ja auch JUnit nebenbei, mal schaun ob es den Aufwand trotz JUnit wert ist.
gepostet vor 17 Jahre, 8 Monate von COrthbandt
Also nach meiner Erfahrung gibt es drei Stufen.
1. Entwicklerversion.
ALLES wird assert()ed. Wirklich jeder Mist. Man bekommt sofort einen Callstack, wo etwas schiefgegangen ist.
Ausserdem: Diverse Konsistenzchecks, eingepackt in #ifdef DEBUG.
Code-Generation: Keine Optimierung, volle Buffer-Checks, volle Type-Info
Das ist die Version, mit der man lokal entwickelt. Bei uns heisst die einfach "Debug", kurz "Dbg".
2. Testversion
Alle assert()s drin. Aber ohne die #ifdef DEBUGs. Code-Generation mit voller Optimierung, volle Buffer-Checks, Debug-Info, Type-Info.
Das ist die Version, die man in der Testphase auf dem Server laufen lässt. Das beinhaltet bei uns ein "crashlog", das die Callstacks verreckter Threads mitlogt. Bei uns heisst diese Version "Check" (Chk).
3. Releaseversion
Keine assert()s. Aber alles was schiefgehen kann wird so gut wie möglich ignoriert/abgefangen/workarounded.
Das ist die Version, die wir als "Release" (Rel) bezeichnen. Hat bisher keiner von unseren Usern gesehen, weil wir in der Beta natürlich auf Chk laufen.
Wichtig: Assert()s haben definitiv nichts in production code verloren. Einfacher Grund: Was passiert, wenn so ein assert() triggert? Der Prozess wird beendet oder hängt.
Ist das auf production sinnvoll? Nein. Selbst ein einfacher Neustart des daemon/service ist sinnvoller. Ein Crash hilft keinem User.
Das heisst natürlich, dass die Release-Version alle möglichen Abfangpfade enthalten muss, um error conditions "graceful" zu behandeln. Faktisch sieht das bei uns so aus, dass an den neuralgischen Punkten erstmal ein assert() kommt und danach der fall-back.
Hat sich in den bisherigen Projekten extrem bezahlt gemacht.
Wie man das im Detail macht hängt sehr von der Platform ab. Bei uns ist alles C++ und wir dumpen tatsächlich einen vollständigen callstack mit allen Params, Adressen usw.
Gottseidank hatten wir sein über zwei Wochen keinen stack dump mehr Release ist auch nicht mehr weit.
gepostet vor 17 Jahre, 8 Monate von COrthbandt
Original von Samson
Original von Todi42
Bei Java gibt es so etwas nicht und da sind die Chancen, das man mit eine Exception wieder zurück zu einem Punkt kommt, in dem das Programm wieder einen definierten Zustand hat viel größer.

Gut, bei C++ ist das logisch. In Java findet man natürlich keine Invarianzen, wie oben geschrieben nutzt man es um Vor- und Nachbedingungen zu prüfen. Das bringt aber auch ne Menge Erleichterung (hoffe ich).
Werde mich mal daran versuchen und prüfen wie es in Java anschlägt. Immerhin hab ich ja auch JUnit nebenbei, mal schaun ob es den Aufwand trotz JUnit wert ist.
< rant >
Exceptions sind eins der dämlichsten Features wo gibt. Punkt.
Wenn ich GOTO meine, schreib ich das auch.
Eine Exception ist ein "Ausnahmezustand". "Ausnahme"... Also nicht der Regelfall. Ergo: Bug. Der Versuch, von einer Exception in irgendeiner Form auf einen zuverlässigen Status zu kommen ist einfach fehlgeleitet.
Exceptions haben in einem Release-Produkt nicht vorzukommen. Was sich die Knallos bei Java mit dem ganzen Scheiss gedacht haben ist mir ein Rätsel.
Einfacher Fehler -> Rückgabewert false (OpenFile z.B.)
Böser Fehler -> Absturz (Division durch Null, Access Violation)
Dazwischen gibt's nichts.
Wenn es _möglich_ ist, auf eine error condition sinnvoll zu reagieren ist eine Exception definitiv der falsche Weg, diese condition dem calling layer zu kommunizieren.
< /rant >
So, das war mal aber sowas von OT. Musste aber sein. Sorry
gepostet vor 17 Jahre, 8 Monate von Agmemon
Sind diese "OldSchool" Assertations heute nicht überflüssig wie ein Kropf, oder übersehe ich da was?
An assertion is a statement in the JavaTM programming language that enables you to test your assumptions about your program.

Genau das mache ich doch mit UnitTests und muss meinen eigentlichen Code nicht mit irgendwelchen if-Anweisungen zukleistern. Wir arbeiten weitgehend Test getrieben (TDD) und werden vermutlich bald zum Verhaltens getriebenen Ansatz (BDD) wechseln.
Erfahrungen mit Fehlverhalten, egal ob die eigenen, die von Testern oder Exception Notifications (die wir per Mail vom System bekommen) schlagen sich dann immer in neuen Unit Tests nieder.
gepostet vor 17 Jahre, 8 Monate von TheUndeadable
> Einfacher Fehler -> Rückgabewert false (OpenFile z.B.)
Wobei ich das zu unspezifisch finde.
Warum ist OpenFile fehlgeschlagen?
Und komm mir bitte nicht mit GetLastError(); Das kann über 'versteckte' API-Aufrufe schon wieder manipuliert worden sein.
Exception als Ausnahmefall sind richtig formuliert. Wenn eine Dateiöffnung fehlschlägt, dann ist es eine Ausnahme, die abzufangen ist. Aber normalerweise soll man sich ein Programm vorher darum kümmern, ob eine Sache fehlschlägt (insbesondere Division by Zero, NullPointer, etc)
gepostet vor 17 Jahre, 8 Monate von Todi42
Original von COrthbandt
Wichtig: Assert()s haben definitiv nichts in production code verloren. Einfacher Grund: Was passiert, wenn so ein assert() triggert? Der Prozess wird beendet oder hängt.
Ist das auf production sinnvoll? Nein. Selbst ein einfacher Neustart des daemon/service ist sinnvoller. Ein Crash hilft keinem User.

Das kommt auf die Applikation an. Wenn ein assert() triggert, dann hat der Prozess sich zu beenden, wenn er das nicht tut, dann hat Deine Laufzeitumgebung einen Fehler. Der Sinn eines asserts ist es, den Prozess so nah wie möglich an der Fehlerquelle zu beenden. Wenn möglich mit einem coredump, den man später debugen kann, um evtl. zu sehen, wie das Programm in den Zustand kam. Läuft so ein Prozess als deamon, der laufen muß, dann wraped man in der Regel da sowieso ein Skript herum, das den Prozess startet, auf dessen Ende wartet und dann wieder startet. Da ist es dann völlig egal, ob der Prozess durch ein assert oder durch ein access violation gestopped wurde. Ein crash hilft einem User natürlich nicht direkt, hilft aber den Entwicklern den Fehler schneller zu finde.
In meinem letzten Projekt haben wir Entwickler uns dafür entschieden asserts im ausgelieferten Produkt zu belassen. Performance Probleme gab es keine, es war nur ab und zu schwierig einem Projektleiter zu erklären, das wir den Prozess mit Absicht abschmieren lassen, weil 1) er es ansonsten wahrscheinlich etwas später ins Straucheln geraten wird und es 2) hilft Fehler zu finden und zu beheben.
gepostet vor 17 Jahre, 8 Monate von Klaus
Mich würde wirklich interessieren, wie dieses "jeden Mist asserten" im Quelltext aussieht, zumal ich auch (versuche) mit C++ zu entwicklen.
Das Exceptionhandling ist dagegen kein Teufelswerk, da es doch recht praktisch ist Fehler zu verallgemeinern.
Beispiel: Ich will einen Socketserver öffnen. Dabei muss ich jeden Piselschritt überprüfen, damit der nächste Schritt überhaupt erfolgen kann. Natürlich kann man hier auch IFs verschachteln bis man dumm und dämlich ist.
gepostet vor 17 Jahre, 8 Monate von COrthbandt
Das oben genannte Beispiel mit dem Socket ist IMHO genau ein Fall, wo Exceptions nichts verloren haben. Dass ein Socket Fehler wirft ist nämlich nicht die Ausnahme, sondern ein ganz normaler Betriebszustand.
Zur Frage wie das mit den Asserts in der Praxis aussieht:
Wir benutzen praktisch nirgends "normale" C-Arrays, sondern eine Template-Klasse. Und die asserted bei allen falschen Index-Zugriffen.
Oder: Wenn eine Funktion bestimmte Grenzwerte für ihre Parameter hat: assert.
Der Database-Layer prüft, ob Readonly-Queries doch etwas geändert haben -> assert.
Beispiel eines Quadtrees:

void PosHash::Quad::Rem(int32 p_iX,int32 p_iY,DeeBase::RowID p_iRow,int32 p_iL,int32 p_iT,int32 p_iR,int32 p_iB)
{
int32 iWH=(p_iR-p_iL+1)/2;
int32 iHH=(p_iB-p_iT+1)/2;
if(m_axSubs.GetSize())
{
ptAssert(m_axEntries.GetSize()==0);
if(p_iX
{
ptAssert(p_iX>=p_iL);
if(p_iY
{
//10
//00
ptAssert(p_iY>=p_iT);
m_axSubs[0].Rem(p_iX,p_iY,p_iRow,p_iL,p_iT,p_iL+iWH,p_iT+iHH);
}
else
{
//00
//10
ptAssert(p_iY>=p_iT&&p_iY
m_axSubs[2].Rem(p_iX,p_iY,p_iRow,p_iL,p_iT+iHH,p_iL+iWH,p_iB);
};
}
else
gepostet vor 17 Jahre, 8 Monate von Todi42
Carsten, Du hast Exceptions einfach nicht verstanden. Sie sind nicht dazu da, in Fehlerfälle, die selten auftreten geworfen zu werden. Fast jede Funktion kann auf einen Fehler (und hierbei meine ich explizit nicht Softwarefehler; dafür sind asserts da) laufen und muß dies dem Aufrufer mitteilen. Wenn man den Fall hat, das der direkte Ausrufer der Funkion und dessen Aufrufer und dessen Aufrufer nichts anderes machen können, als den Fehler weiter zu reichen, hat man wieder den klassischen Fall, wo die Hälfte des Codes sich mit Fehler weiter reichen beschäftigt ist. Und genau in den Fällen, wo der Aufrufer wahrscheinlich nichts mit dem Fehler machen kann, als ihn weiter zu reichen, sind exceptions das beste Mittel. In dem Beispiel mit der Netzwerkverbindung, was soll die SchreibeStringAufStream Funktion den mit einem Netzwerkfehler machen? Sie wird ihn weiter an die SchreibeNameUndAdresseAufStream Funktion reichen, die reicht ihn weiter an die SchreibeKundenAufStream Funktion und die wieder weiter an die SendeNeuenKundenAnServer, die dann die Fehlerausschrift machen kann, das das Anlegen eines neuen Kundens aufgrund eines Netzwerkfehlers nicht geklapt hat.
@Klaus: Assert dokumentieren auch ganz prima die Annahmen, die der Autor an einer bestimmten Stelle macht.

unit_list& unit_list:perator-=(const units& rhs)
{
list_t::iterator pos = std::lower_bound(list_.begin(), list_.end(), rhs);
assert( pos != list_.end() && pos->type() == rhs.type() );
assert( pos->amount() >= rhs.amount() );

if ( pos->amount() == rhs.amount() )
list_.erase(pos);
else
pos->remove(rhs.amount());
return *this;
}
gepostet vor 17 Jahre, 8 Monate von Lunikon
Exceptions einfach als Blödsinn abzutun halte ich schon für etwas...naja....krass
Einen fehler über den Returnwert einer Methode auszugeben ist doch vorletztes Jahrhundert und alles andere als sinnvoll. Wenn meine Methode ein Objekt oder null zurückgeben kann/soll, wie will ich dieses Ergebnis mit einem Fehlerzustand überladen? Da ist es doch viel besser, eine Exception zu werfen. Ich denke um ganz unerwartete Fehler geht es doch dabei auch garnicht. Im Gegenteil: Wenn ich einen Socket, ein File oder sonstwas verwende muss das Programm doch von dem Fall ausgehen, dass der Zugriff nicht funktioniert und entsprechend damit umgehen. Exceptions sind hier in meinen Augen eine sehr elegante Lösung.
gepostet vor 17 Jahre, 8 Monate von None
Original von COrthbandt
< rant >
Exceptions sind eins der dämlichsten Features wo gibt. Punkt.

Als Java-Mensch sehe ich das komplett anders. Eine Exception hat (weder intern noch in der Struktur) etwas mit goto zu tun. Im Gegenteil...
java.sun.com/docs/books/tutorial/essential/exceptions/advantages.html
Nur zur Verteidigung...
Letztendlich heißt es eben auch für C++ und Java: leben und leben lassen. Es gibt auch ungefähr 1000 Dinge ich die an C++ hasse und akzeptiere. Gewisse Vorteile sind damit immer verbunden, sicher. Aber eben auch ne Menge Nachteile.
Je nachdem wie du das siehst, wirst du ne andere Sprache wählen
Also keep cool
gepostet vor 17 Jahre, 8 Monate von COrthbandt
Das Problem dabei ist (wird teilweise durch throws-spec umgangen), dass exceptions als Teil des call interface behandelt werden müssten.
Genau dieses Interface kann sich nun durch tiefer liegenden Code aber beliebig ändern, ohne dass dies in höheren Ebenen sichtbar wird.
In der üblichen Ausprägung sind exceptions nichts anderes als versteckte out-of-band return values.
Mir ist schon klar, dass in Java on Exceptions praktisch nichts geht, da die Class Libs nun mal so ausgelegt sind. Ich halte es aber (wie gesagt meine subjektive Ansicht) für einen Design-Fehler.
Ich halte allerdings auch Garbage Collection in der Form wie es Java und C# machen für fehlerhaft. RAII gilt IMHO für Speicher genauso wie für Filehandles, Sockets, whatever. Die getrennte Behandlung dieser Resourcen macht gerade im Zusammenspiel mit Exceptions das Leben unnötig schwer. Das sieht man schön an den Verrenkungen mit "finally", die mit sauberer scope lifetime der Objekte nicht notwendig wären.
Aber ich hatte meinen Post ja nicht umsonst als RANT gekennzeichnet. Das die Meinungen bei dem Thema auseinandergehen ist völlig klar und auch gut so.
gepostet vor 17 Jahre, 8 Monate von Agmemon
Eine sehr schöne Diskussion. Da macht man sich mal wieder Gedanken darüber, was man so zusammen programmiert.
Wenn ich mir Carstens Beispielcode ansehe, muss ich unweigerlich an Design By Contract denken, zumindest bei einem Teil der Assertations. Und ich muss zugeben, dass der Code durch die Assertations optisch sauberer ist, als wenn man es manuell über if-Anweisungen bewerkstelligen würde. Was mir aber gar nicht zusagt ist, was passiert, wenn die Prüfung in der Assertation fehlschlägt. Wenn ich es richtig in Erinnerung habe und es hier richtig verstanden habe, wird die Anwendung einfach beendet. Das mag bei kleinen Sachen ja ganz OK sein, aber nicht, wenn man mit komplexen Zuständen zu tun hat.
Das ist mit Exceptions dann schon ein wenig besser, wenn man sie richtig verwendet. Aber auch bei den Exceptions gibt es einfach Sachen die dämlich sind. Ich hatte gerade die Tage mit meinem Sofrtwaretechnik Professor eine Diskussion darüber, was Java EE 5 betrifft. Dort sind Methoden in der Geschäftslogik durch Transaktionen gekapselt. Sprich Datenbankänderungen werden erst weggeschrieben, wenn die Methode verlassen wird. Wenn dabei ein Fehler auftritt, wird eine Exception geschmissen. Da man aber die Methode der Geschäftslogik verlassen hat, und nicht mehr reagieren kann, landet die Exception in der Präsentationsschicht. Die Exception muss also Clientseitig bzw. in der Webschicht behandelt werden, was völlig für die Füsse ist, da man nicht mehr richtig reagieren kann.
Zu dem sollte man immer Bedenken, dass Exceptions keine Mittel zur Steuerung der Flusskontrolle darstellt, auch wenn es manchmal verlockend ist.
Was den überbewerteten Hype UnitTesting betrifft, hast Du vermutlich recht Carsten. Wobei das auch daran liegen mag, dass die wenigsten es wirklich können. Viele wähnen sich mit UnitTests nämlich in falscher Sicherheit, weil sie nur die fachlichen Minimalanforderungen mit Tests abdecken und keine negativ Tests schreiben. Vom Thema Testabdeckung nach den geltenden Standards (R1 - R3) will ich gar nicht reden.
gepostet vor 17 Jahre, 8 Monate von None
Über Java EE5 muss man sich nicht streiten. Das Ding geht ziemlich am strikten OOP vorbei. Daher bastelt Sun ja auch schon unter Hochdruck an der 6er Version.
Aber wozu denn diese ganzen Dinge verwenden? Es geht auch super ohne diesen ganzen Enterpriese Mist.
Dazu gibts Hibernate und Struts. Hibernate wird für die neue EE (Persitenz-)Generation sogar Pate stehen und Referenzimplementation werden, laut Gerüchten die man so hört.
gepostet vor 17 Jahre, 8 Monate von abuzeus
Ich zitiere Bjarne Stroustrup:
"Das schöne an C++ ist, dass man sich bei fast allen Sprachmitteln entscheiden kann, sie NICHT zu nutzen, und man bezahlt dann auch nicht dafür."
Deswegen lässt sich in C++ auch einigermassen ohne Exceptions programmieren, auch wenn man natürlich einen Schritt näher an aufgebohrtem C ist ;-). Das Problem an Exceptions ist nur, dass viele überhaupt nicht verstanden haben, wozu sie eingesetzt werden. Ein beliebter Fehler in der Javafraktion ist es, zu glauben: "Viel try/catch = viel gut" - das ist aber falsch. Guter exceptionsicherer Code hat fast kein try/catch. Mit RAII und Smartpointern bzw. Sentries kann man verblüffende Effekte erzielen, und dann werden Exceptions auch sinnvoll, als eben der Programmpfad, der nur in ungewollten Ausnahmesituationen auftreten soll, der aber üblicherweise noch nicht das Ende der Welt bedeutet. Paradebeispiel: bad_alloc. Und was C++ da im Bereich new_handler usw. zur Verfügung stellt, ist krass - aber man muss es eben nicht benutzen (ist aber extrem hilfreich, wenn man nicht die Standardspeicherverwaltung haben will, was bei großen oder systemnahen Projekten definitiv der Fall sein wird). Dass das ganze in java etwas übertrieben wurde, tut Sun vermutlich auch schon leid, aber das lässt sich ohne größeres Aua jetzt vermutlich nicht mehr ändern.
Ich möchte in diesem Fall allen das Buch "Exceptional C++" von Herb Sutter ans Herz legen, das ist für mich eines der 5 bis 10 wichtigesten Bücher zu dem Thema. Sogar Java- oder C#-Programmierer können noch etwas lernen. Man sieht C++-Code vermutlich nie wieder mit den gleichen Augen, wenn man das Buch gelesen hat.
Zu assertions: Die haben im Produktivcode nix zu suchen. Eine Assertion ist eigentlich etwas, was NIEMALS fehlschlagen sollte. Java ignoriert ja standardmässig in Produktivcode die Assertions, und das hat auch seinen Grund (btw: Es gibt in C++ auch compile-time Assertions. Sehr nützlich).
Und zu guter letzt: Es gibt auch formale Techniken zur Softwareverifikation, die auch Fehlerfreiheit garantieren können, soweit ich weiss. Allerdings ist sowas nicht trivial, nicht unbedingt common knowledge und hat auch durchaus was mit Mathematik zu tun. In 2 bis 3 Jahren kann ich mehr dazu sagen, das wird vermutlich in mein Spezialgebiet fallen ;-)
gepostet vor 17 Jahre, 8 Monate von exe
Ich denke man kann Exceptions (in Java) nicht wirklich als klassische Ausnahme sehen sondern eher als eine Art alternativer Rückgabewert wenn der Standardwert keinen Sinn macht.
Zum Beispiel das Parsen eines Strings als Zahl:
int foo = Integer.parseInt("123");

funktioniert wunderbar, nur nicht wenn ich statt "123" ein "asdf" schreibe. 0 oder -1 zurückgeben ist da nicht wirklich eine Option da es nicht von einer gültigen Konvertierung unterscheidbar wäre. Was tun? Eine NumberFormatException werfen auf die der Aufrufer wunderbar reagieren kann.
Wenn ich in Java einen irreparablen Fehler (OutOfMemory, StackOverflow, etc.pp.) habe werfe ich einen "Error". Bei zu erwartenden Probleme (wie beim Beispiel des Socket IO) eine checked Exception, bei "leichten" Fehlern wie dem Integerparsing einen RuntimeException und alle sind glücklich.
Exceptions auf die man nicht mehr vernünftig reagieren kann sind natürlich so eine Sache. Ich fange die trotzdem meist ab um sie zu loggen, jenachdem wie schwer sie sind. Wenn z.B. der Handler eines einzelnen HTTP-Requests mit einer NPE abbricht möchte ich nicht den ganzen Server mit einem Stackdump beenden. Da reicht es die Exception abzufangen, zu loggen und den Request abzubrechen.
Man muss aber in der Tat sagen, dass bei Java an manchen Stellen mit den Exceptions Schindluder getrieben wurde, was letztendlich gezwungenermaßen (checked exceptions sei dank) zu try/catch/catch/catch/catch-Wüsten führt.
Asserts dagegen sind eine tolle Sache. Und so wie ich das sehe eigentlich nicht so anders als UnitTests. Die Tests machen letztendlich auch nur diverse asserts, nur halt mit eigenen assert-Funktionen anstatt den entsprechenden Sprachkonstrukten. Der Unterschied ist nur, dass die UnitTests das eben bei Bedarf auf beliebigen Code ausführen, die Asserts nur dann, wenn man den Code "händisch" ausführt.
gepostet vor 17 Jahre, 8 Monate von TheUndeadable
Wie schon geschrieben, Exceptions als Unding abzutun finde ich persönlich etwas krass. Die Rückgabe eines Fehlers über den Rückgabewert finde ich persönlich auch etwas suboptimal.
Wo ist der große Unterschied zwischen:

function int Caller()
{
if ( CallFunction () != SUCCEED )
{
return FAILED;
}
return SUCCEED;
}
und

function void Caller()
{
try
{
CallFunction();
}
catch ( Exception exc )
{
// Behandel und/oder throw exc weiter
}
}
Falls man die Exception nicht behandeln möchte/behandeln kann, so muss man sie zumindest in C# nicht fangen. Wenn die keine Funktion fängt, so wird sie bis an das Betriebssystem weitergereicht, wo man dann einen schönen Stack-Trace erhält. ( depon.net/nopaste/s.aspx?i=6 ). Wenn ich mir diesen dann per Fehlerbericherstattung zuschicken lasse, weiß ich genau was fehlgeschlagen ist. Im Debug-Modus erhalte ich auch die Zeilennummern.
Zum Thema 'Stackbasierte' Datentypen und finally gibt es zumindest in C# das Schlüsselwort 'using'
function void a()

{
using ( File file = new File ( "abc", FileMode.Write ) )
{
file.Write(...);
}
}
Nur innerhalb der Using-Syntax bleibt das File-Objekt bestehen. Wird der Using-Scope aus egal welchem Grund verlassen (Thread-Abort, Exception, normaler Datenfluss), so wird das file-Objekt geschlossen (genauergesagt: Disposed). Leider muss man wissen, welche Objekte das Interface IDisposable implementiert. Aber im Laufe der Zeit bekommt man ein gutes Gefühl dafür.
Und Negativ-Beispiele von Return-Value Überprüfungen sieht man immer in der COM-Programmierung:
opensource.creative.com/mtp_xfer_art_code.txt
Stichwort: if ( SUCCEEDED ( Function ) ) { ... }
Und wie schon geschrieben: Über den Return-Value kannst du nicht den Art des Fehlers ausgeben. In der von mir geposteten Exception weiß ich genau warum der Zugriff auf diese Datei fehlgeschlagen ist. Der Kunde hat nicht das Netzlaufwerk getrennt, ein anderes Programm (oder gar das eigene) hatte noch Zugriff auf die Datei.
Es steckt vielleicht eine Design-Philosophie dahinter, aber ich persönlich kann auf Exceptions nicht mehr verzichten.
Wobei:
Gerade bei parseInt und anderen Dingen schaue ich vorher lieber mit der Funktion 'IsNumber' drüber, bevor ich sie zum Converter schicke. Ich will Exceptions soweit wie möglich vermeiden, da diese unter nahezu keiner Programmierumgebung wirklich performant sind.
> dass exceptions als Teil des call interface behandelt werden müssten.
Ist auch nicht zwingend so. Bei den meisten Programmiersprachen muss eine Funktionsdeklaration nicht angeben welche Exceptions hier fliegen können. Die Java-Variante finde ich persönlich etwas grausam...
gepostet vor 17 Jahre, 8 Monate von COrthbandt

> dass exceptions als Teil des call interface behandelt werden müssten.
Ist auch nicht zwingend so. Bei den meisten Programmiersprachen muss eine Funktionsdeklaration nicht angeben welche Exceptions hier fliegen können. Die Java-Variante finde ich persönlich etwas grausam...

Und genau da sehe ich halt das Problem. Die Art der evtl. geworfenen Exceptions ist Teil der API, kann sich aber ändern ohne dass das zu Änderungen am sichtbaren Interface führt.
Es ist IMHO kaum sinnvoll, wenn dann irgendeine Funktion plötzlich Exceptions aus z.B. Zahlen-Parsen weiterwirft. Wenn man nicht aufpasst kann aber genau das passieren.
Bei der abartigen Menge an Exceptions die Java und C# so erzeugen ist die korrekte Behandlung auch ein potentielles Performance-Loch, da Exceptions in allen derzeitigen Modellen ausgesprochen teuer sind.
Insofern sehe ich nicht, warum das ein sinnvolles Modell sein soll.
1. Teuer
2. Fehleranfällig (da verdecktes Interface)
Das Argument der erweiterten Fehlerinformation ist natürlich grundsätzlich nicht von der Hand zu weisen. Dafür gibt es aber auch andere mögliche Konstrukte, die den Overhead von Exceptions nicht mit sich bringen und auch kein getarnter Return Value sind.
gepostet vor 17 Jahre, 8 Monate von None
Der Performanceverlust hält sich bei Java im Gegensatz zu C++ in Grenzen. Java verbrät nur Ressourcen bei geworfenen Exceptions und bei C++ wird - egal ob nun geworfen oder komplett unbenutzt - Ressourcenreservierung betrieben.
Genau hats mir mal mein prof erklärt warum das so ist, aber ich bekomms nicht mehr so richtig zusammen.
Aber allgemein zu Performance: heute musst du in aller Regel nicht mehr so auf Performance achten. Im Gegenteil: die Tendenz geht in Richtung Kapselung und Black-Boxing (was vor 5 Jahren noch ein innovativer Ansatz war ist heute Standard). Performance darf für Vorteile geopfert werden. Es macht keinen Unterschied ob ich nun 10 Takte oder 60 Takte brauche. Bei nem Dual Core mit jeweils 2,4 Ghz ist das sowas von uninteressant.
Performance hat heute bei weitem nicht die höchste Prioriät mehr (im Normalfall - Ausnahmen gibt es immer). Und wenn ich mir die Wiederverwendbarkeit ansehe, ist das auch verdammt gut so
Exceptions sind sehr hilfreich und verändern, wenn ich das will, die drüberliegenden Klassen. Ich brauch doch keine Methode a la sqlAbfrage.warErfolgreich(), diese Art ist veraltet und wird immer mehr verdrängt. Wenn es einen Fehler - gleich welcher Art - gab, werde ich informiert und kann Schritte einleiten.
Hollywood-Prinzip: "Don't call us, we will call you"
Das Ganze bildet die Grundlage jedes GUIs und Exceptions sind eine moderne Form dieses Prinzipes.
Das Ganze ist übrigens performanter als das Aufrufen von Operatoren, denn wird in Java keine Exception ausgelöst, verbraucht sie keine Ressourcen. Der Methodenaufruf schon. Aber wie schon gesagt, die Performance ist zweitranig eigentlich.
Werd noch mal nachfragen wie das Exception-Handling intern so bei Java ablief.
gepostet vor 17 Jahre, 8 Monate von Todi42
Original von Samson
Der Performanceverlust hält sich bei Java im Gegensatz zu C++ in Grenzen. Java verbrät nur Ressourcen bei geworfenen Exceptions und bei C++ wird - egal ob nun geworfen oder komplett unbenutzt - Ressourcenreservierung betrieben.
Genau hats mir mal mein prof erklärt warum das so ist, aber ich bekomms nicht mehr so richtig zusammen.

Das ist mit Verlaub: Blödsinn. In C++ kann man exceptions so implementieren, das überhaupt kein Overhead entsteht, wenn keine Ausnahme geworfen wird und das ist damit sogar schneller als das konservative Testen und Weiterreichen von Fehlercodes.
Siehe: groups.google.de/group/de.comp.lang.iso-c++/tree/browse_frm/thread/e514df326ce7c045/008f5f1a240a1bc2?rnum=31&hl=en&q=exception+robitzki+stack&_done=%2Fgroup%2Fde.comp.lang.iso-c%2B%2B%2Fbrowse_frm%2Fthread%2Fe514df326ce7c045%2F3bc3703fed7076cf%3Ftvc%3D1%26q%3Dexception%2Brobitzki%2Bstack%26hl%3Den%26#doc_c19c7d076dd16dad
gepostet vor 17 Jahre, 8 Monate von None
Ich kanns dir nich mehr genau sagen warum. Das hängt damit zusammen das native Sprachen da einen Interpretationsnachteil gegenüber Java (& anderen interpretierten Sprachen) haben.
In ner Woche wird die Vorlesung wieder auf den Punkt zurückkommen, da frag ich nochmal nach
Bin übrigens kein C++-Experte, daher mag es schon sein das man es anderes Implementieren kann. Ich geh hier vom 0815-Code der mir bekannt ist aus (der Rest interessiert mich gar nich, denn Spezialanwendungen werd ich in Java implementieren :p).
gepostet vor 17 Jahre, 8 Monate von Todi42
Original von Samson
In ner Woche wird die Vorlesung wieder auf den Punkt zurückkommen, da frag ich nochmal nach
Bin übrigens kein C++-Experte, daher mag es schon sein das man es anderes Implementieren kann.

Die meisten Professoren, denen ich wärend meines Studiums über den Weg gelaufen bin, würde ich im Nachhinein auch nicht als Experten bezeichnen ;-)
gepostet vor 17 Jahre, 8 Monate von None
Original von COrthbandt
Da hat Dir aber jemand einen Bären aufgebunden.
Java ist keine interpretierte Sprache. Schon mal von JIT gehört?
de.wikipedia.org/wiki/JIT-Compiler

Das ist kein Widerspruch
Der JIT ist TEIL des Ganzen (sowie der Interpreter auch). Und der JIT interpretiert den Bytecode je nach Platform übrigens auch.
Aber ich will mich hier nicht über solche Dinge unterhalten, viel wichtiger ist mir das Thema an sich.
Edit: falls es dich interessiert les doch mal die Sun Doku zur VM (und der Interpretation von Bytecode). Ist sehr interessant.
java.sun.com/j2se/1.5.0/docs/guide/vm/index.html
Original von Todi42

Die meisten Professoren, denen ich wärend meines Studiums über den Weg gelaufen bin, würde ich im Nachhinein auch nicht als Experten bezeichnen ;-)
Da hast du sicher Recht. Der bisherige Höhepunkt war Statistik und Internetprogrammierung (sprich also JSP und Beans).
Aber der Prof ist wirklich klasse, selten hat jemand so viele Hintergrundinfos geliefert (von Metaprogrammierung bis Assertions hat er bisher zu allem was gezeigt neben der Vorlesung). Ist sehr versiert der Mann. Zumal er bei Borland für den C++-Compiler zuständig war und ihn mitgeschrieben hat.
Hoffe doch er wusste was er da tat
gepostet vor 17 Jahre, 8 Monate von exe
Original von Samson
Aber der Prof ist wirklich klasse, selten hat jemand so viele Hintergrundinfos geliefert (von Metaprogrammierung bis Assertions hat er bisher zu allem was gezeigt neben der Vorlesung). Ist sehr versiert der Mann. Zumal er bei Borland für den C++-Compiler zuständig war und ihn mitgeschrieben hat.
Hoffe doch er wusste was er da tat

OT: ich weiss zwar nicht wie gut der Compiler ist, aber der Borland C/C++ Builder ist eine Kathastrophe sondersgleichen. Selten so ein unbenutzbares Stück Entwicklungsumgebung gesehen ..
gepostet vor 17 Jahre, 8 Monate von None
Unter uns gesagt: ich weiß auch nicht wie es Borland mit Together schaffen konnte Marktführer im Bereich Enterpriese-UML zu werden. Das Teil is eine einzigste Seuche.
Aber ich halt mich da zurück an der Uni, in 6 Wochen is wieder Klausurphase und zur Sicherheit wird erst danach wieder gemeckert :p
gepostet vor 17 Jahre, 8 Monate von knalli
Ich hatte mich erstmal zurückgehalten, bevor ich nachher selber selbst damit kentere: Ich mache selber derzeit im Rahmen eines Projekts eine Implementierung nach einer selbst erstellten Spezifikation. Dabei habe ich mich entschieden, die Vorbedingungen mit Exceptions in Java zu lösen. Das Projekt ist nicht für jemanden bestimmtes, es wrd nach diesem Semester wahrscheinlich keiner mehr nutzen - sprich: Ich kann alles mal ausprobieren.
Es ist durchaus angenehm, wenn ich in meinem Schachspiel sehen kann, warum ein Zug nicht gültig war (Aufgabe: gesamte Schachlogik - ohne KI). Das ein Zug nicht gültig war, ist ja schön - aber warum?
Mit Exception sspart man die sämtlichen Statusabfragen, die man ja bräuchte, wenn man keine Exceptions hätte. Und ich finde auch, das if-/else-Konstruktue wesentlich unleserlicher sind (wenn sie größer und komplexer werden), als einfache Würfe. Wer mir jetzt mit Goto kommt (ack, kann ich ebenfalls nicht ausstehen) - das ist für mich doch ein anderes Schema. Versuche, und fange ggf auf. Nichts anderes. Im Gegensatz zu Goto ist das durchaus leicht nachzuvollziehen, und mit Werkzeugen wie Eclipse (also IDE) sogar leicht zu überschauen und zu steuern (Thema nicht gecheckte Exceptions).

Auf diese Diskussion antworten