Operator überladen - Architekturverständnis ?
-
Hallo,
folgender Sachverhalt: in einer Anwendung arbeite ich mit Bitmaps auf die ich verschiedene Operationen durchführe. Unter anderem wollte ich dafür den "-"-Operator überladen. Versuch 1:
public static Bitmap operator -(Bitmap b1, Bitmap b2)
führt zu: One of the parameters of a binary operator must be the containing type
Obwohl sich mir bereits der Sinn dieses Fehler nicht 100%ig erschließt, die nächste Variante probiert: Versuch eine eigene Bitmapklasse abzuleiten, um diese dann als Parameter anzugeben. Das funktioniert auch nicht, da System.Drawing.Bitmap versiegelt ist. Mir ist klar, dass ich um das gleiche zu erreichen auch eine x-beliebige Funktion deklarieren kann. Aber mir geht es hier hauptsächlich um das Architekturverständnis und den Sinn des Überladen von Operatoren. In meinen Augen ist das Überladen des Operators in meinem Fall ein gerechtfertigtes Vorgehen, trotzdem erlaubt es die Sprache nicht. Warum ?
Fruchtbare Diskussion erwünscht
Gruß
Christian
-
Hi,
Erstmal denke ich dass hier (bei zwei Bitmaps) operator- overloading keinen Sinn macht.
Ich denke es wäre vom Design her gesehen sinnvoller Methoden mit Namen anzubieten.Zu deinem konkreten Problem:
Die Definition muss innerhalb der Klasse sein.
(Das sagt die Fehlermeldung.)Hier gibt es sinnvolles Beispiel: http://www.csharphelp.com/archives/archive135.html
Grüsse Simon
-
Hallo,
ich will die Farbwerte der Bitmaps pixelweise subtrahieren. Meiner Auffassung nach macht die Operation "-" da sehr viel Sinn.
"Die Definition muss innerhalb der Klasse sein. "
Ja und genau das geht ja nicht weil versiegelt.
Das Beispiel ist doch genau das gleiche wie bei mir, ob ich nun Komplexzahlen addiere oder Pixelwerte subtrahiere ist egal.
Gruß
Christian
-
CBecker schrieb:
Das Beispiel ist doch genau das gleiche wie bei mir, ob ich nun Komplexzahlen addiere oder Pixelwerte subtrahiere ist egal.
Technisch betrachtet hast Du recht. Fachlich betrachted liegst Du so falsch wie man nur liegen kann.
Beispiel:
5 + 5 = ?
Da weis Jeder sofort was gemeint ist.
Bitmap + Bitmap = ?
Ja, was kommt denn da raus wenn man zwei Bitmaps addiert? Aus dem Programmfluß kann da niemand sofort drauf kommen ohne das er sich den überladenen Operator anschauen muss. Und auch wenn Du es nciht glauben magst, selbst Du selber wirst es irgendwann nicht mehr genau wissen.
Bitmap.AddColorValues(Bitmap);
So eine Funktion dagegen sagt sofort wieder aus worum es geht.
Natürlich kannst Du Dich darauf versteifen das es aber doch funktioniert und technisch möglich ist bla bla... Und damit auf den Zug der ewig mittelmässigen Programmierer aufspringen die nie begreifen werden das es mehr gibt als die reine technische Funktion...
-
Hallo,
du nennst einige valide Punkte. Dass der Fehler auch in meiner Denkweise liegen kann habe ich keineswegs ausgeschlossen wie man ja schon dem ersten Posting indirekt entnehmen kann.
Trotzdem lässt dein Vergleich die Frage nach dem Sinn des Überladens offen:
Du sagst:
5+5 weiß jeder
Bitmap+Bitmap weiß nicht jederDaraus muss man dann aber auch folgern, dass, um beim Beispiel der Addition von Zahlen zu bleiben, der Plusoperator nichts anderes macht als eben diese Zahlen zu addieren (denn es "weiß" ja jeder). In dem Moment, wo man dort etwas anderes macht, weiß es eben nicht mehr jeder und man müsste wieder nachschauen. Man legt sich also darauf fest, dass man den Plusoperator so überlädt, dass man "weiß" was er macht. Und in diesem Fall stelle ich mir die Frage warum überhaupt überladen ? Denn selbst wenn ich eine eigene, tolle, neue mathematische Definition für mein Plus finde müsste ich es ja dann auch wieder mitteilen (hey, es heißt zwar plus, aber es addiert halt doch nicht so wie im gängig genutzten Zahlenraum).
Die Frage ist also: warum überladen, wenn ich dann doch nur das machen kann, was jeder weiß, ohne in den überladenen Operator zu schauen ?
Das leuchtet mir als wahrlich mittelmäßigem Programmierer nicht ein.
Gruß
Christian
-
Die Logik dahinter ist so einfach wie sinnvoll: Eine als 'sealed' markierte Klasse ist quasi unantastbar, d.h. im Sinne des Entwicklers fertig und unveränderbar. Wenn Du einfach inen Operator hinzufügen könntest, dann hättest Du die Semantik der Klasse geändert.
Ab C# 3.0 ist dieses Ändern (im Sinne von Hinzufügen) aber explizit Teil der Sprache geworden, nämlich durch die sog. Extension Methods, die es erlauben, einer bestehenden Klasse neue Methoden hinzufügen zu können. Purer syntaktischer Zucker, denn semantisch betrachtet handelt es sich um ganz normale statische Methoden.
Das ist allerdings bei Operatoren nicht anders, man könnte also argumentieren, dass es auch erlaubt werden sollte, Operatoren hinzuzufügen. Tut man aber nicht, und zwar aus folgendem Grund (soweit mein Verständnis):
Klassen besitzen einen Satz fundamentaler Operationen, und dann noch erweiterte Funktionen. Diese erweiterten Funktionen sind anpassbar (eben durch statische Methoden, oder mit Syntaxzucker durch Erweiterungsmethoden). Der Satz der fundamentalen Operationen hingegen ist und soll fest sein. Das ist näher betrachtet durchaus sinnvoll. So kann man bei einem Auto z.B. einige Gadgets hinzufügen (ja, wer mag sie nicht, diese tollen Heckspoiler?). Aber niemand würde auf die Idee kommen, den Motor zu entfernen. Genausowenig kann man den Motor einfach durch einen anderen austauschen. Es gibt zwar Autos, bei denen man z.B. auf Biotreibstoff umsteigen kann, das funktioniert aber i.d.R. nur, wenn das Auto speziell dafür konzipiert worden ist. Übertragen auf OOP sollte man also die Finger von fundamentalen Operationen lassen, es sei denn, die Klasse ist explizit hierfür gebaut worden, z.B. durch Komposition oder über das Template Method Pattern.
So. Und jetzt geht das ganze noch einen Schritt weiter. Für bestimmte absolut fundamentale Funktionen gibt es noch einen zusätzlichen Syntaxzucker in Form von Operatoren. Operatoren sollten aber spärlich eingesetzt werden. Quasi jeder Style Guide warnt vor dem exzessiven Einsatz. Nur die fundamentalsten, idiotensichersten Operatoren sollten solche Shortcuts besitzen. Daher die Einschränkung bei der Erweiterbarkeit.
Man könnte auch gut anders argumentieren, wie das z.B. Sprachen à la Ruby tun. Das bringt aber eben nicht nur Vorteile mit sich.
-
CBecker schrieb:
Daraus muss man dann aber auch folgern, dass, um beim Beispiel der Addition von Zahlen zu bleiben, der Plusoperator nichts anderes macht als eben diese Zahlen zu addieren (denn es "weiß" ja jeder).
Solange es sich um Zahlen handelt, ja. Aber hier handelt es sich um komplexere Objekte. Wenn du zwei Strings hast und die mit + aneinander fügst erwartest du wohl auch nicht als erstes das dabei die einzelnen Zeichen aufaddiert werden, sondern eher ein hintereinander anfügen (Auch wenn ich hier schon gewisse Erklärungsprobleme sehe).
Als ich Bitmap+Bitmap gesehen habe dachte ich persönlich eher an das Ergänzen eines Bildes um ein Anderes (mit den entsprechend vergrößerden Dimensionen). Bei Bildern ist es halt problematisch, da es hier sehr unterschiedlich gemeint sein kann.
Man legt sich also darauf fest, dass man den Plusoperator so überlädt, dass man "weiß" was er macht.
Wann weiß man es? Bei Zahlen, okay... Da ist man es schon aus der Schule so gewohnt. Bei allen komplexeren Objekten muss man sich aber fragen: Wie könnte es am ehesten interpretiert werden. Ich würde hier auf die typische 90% Regel zurückgreifen. Ist der Sinn des Operators für etwa 90% der Anwender ersichtlich? Wenn ja, dann ist es eine gute Idee ihn so zu verwenden. Ansonsten sollte man sich überlegen ob es wirklich sinnvoll ist.
cu André
-
CBecker schrieb:
Die Frage ist also: warum überladen, wenn ich dann doch nur das machen kann, was jeder weiß, ohne in den überladenen Operator zu schauen ?
Das leuchtet mir als wahrlich mittelmäßigem Programmierer nicht ein.
Es liegt bei Dir ob Du Mittelmaß bleiben willst oder anfängst über Dinge nachzudenken, die in jedem besseren Buch zu dem Thema immer und imerm wieder auftauchen.
Mal ein Beispiel. Jeder von uns weis wie Pedale in einem Auto funktionieren. Stell Dir mal vor diese Pedale wären Operatoren. Was wenn ein Hersteller jetzt auf die Idee kommt das Gaspedal zu "überladen" und ihm eine andere Funktion gibt als die vorgesehene, sagen wir for argument sake, er überlädt das Gaspedal mit der Funktion des Anlassers und das Bremspedal mit der Funktion des Gaspedals. Die Kupplung überlädt er als Bremse weil er aufgrund des Automatik-Getriebes keine Kupplung braucht.
Nenn mir einen einzigen technischen Grund der dagegen spricht sowas zu machen? Immerhin hat das Auto immer noch alle Funktionen, man kann es Starten, Bremsen und Beschleunigen. Technisch gesehen ist also alles in Ordnung.
Trotzdem bauen alle Autohersteller aktuell Autos nach dem gleichen Design-Pattern: Rechts Gas, Mitte bremse, links Kupplung.
Warum? Einen technischen Grund dafür gibt es nicht. Allein die Fachlichkeit ist hier entscheident. Man baut diese Pedale so wie alle sie erwarten um die Anzahl der Unfälle zu verringern.
Und hier kommen wir zurück zu Deiner Situation. Natürlich ist es technisch Möglich den -Operator beliebig zu überladen, aber es ist ein mieser Stil weil Du das dann sicher auch bei anderen Sachen machst und am Ende Code erzeugst der voller Stolperfallen ist.