Hallo,
aktuell möchte ich ein kleines Miniprojekt in C# erstellen und einen
Temperatursensor auslesen - gerne würde ich hierbei auch OOP anwenden.
In wie weit organisiert man alles in Klassen?
Muss ich also eine Klasse "Temperatur" anlegen? (hier könnte man ja
zwischen Fahrenheit und Celsius unterscheiden?
Außerdem muss ich ja sicher eine Klasse Sensor anlegen. Wie weit würde
man das ganze noch aufdroeseln?
Vielen Dank,
Kevin
Kevin schrieb:> (hier könnte man ja> zwischen Fahrenheit und Celsius unterscheiden?Brauchst du denn beides?
Nichts ist schlimmer, als Klassenhierarchien "auf Vorrat" zu
vervollständigen.
Das kommt auf das Projekt an. Aber prinzipiell hört sich das schon gut
an. Eine Klasse Temperatur (könnte man auch von einer allgemeineren
Klasse für Größen mit Einheiten ableiten, ist hier aber wohl zu viel des
Guten).
Die hat dann z.B. get/set unit und get/set value.
Das Projekt scheint ja klein zu sein, da bringt OOP nicht viel.
Interessant wird es, wenn du verschiedene Sensoren hast. Wenn du die
Implementierungen von einer schönen Klasse "Sensor" ableiten kannst,
dann wird es praktisch. Dazu musst du dir aber gut überlegen, was eine
generische Sensor-Klasse können soll und was nicht.
super, vielen Dank für eure Antworten.
Dann bin ich ja schon einmal nicht auf dem Holzweg.
>> Nichts ist schlimmer, als Klassenhierarchien "auf Vorrat" zu> vervollständigen.
Ist das wirklich so? Ich dachte gerade für sowas wäre OOP super?!
Kevin schrieb:> super, vielen Dank für eure Antworten.>> Dann bin ich ja schon einmal nicht auf dem Holzweg.>> Nichts ist schlimmer, als Klassenhierarchien "auf Vorrat" zu> vervollständigen.>> Ist das wirklich so? Ich dachte gerade für sowas wäre OOP super?!
Over Engineering geht auch ohne OOP.
"You ain't gonna need it" schon mal gehört?
Flache Hierarchien sind besser denn Vererbung koppelt am stärksten,
besonders wenn mann nicht nur die Schnittstellen sondern auch die
Implementierung erbt.
Jan Hansen schrieb:> Die hat dann z.B. get/set unit und get/set value.
Beeep, beep, beep, Anti-OO Alarm.
Ein gutes Objekt macht seinen internen Zustand nicht von Außen
erreichbar.
Kevin schrieb:> Ist das wirklich so? Ich dachte gerade für sowas wäre OOP super?!
Ja, dafür ist OOP super. Sie verleitet dazu, Dinge vorzusehen, die kein
Mensch braucht.
Beispiel: Du entwickelst eine Software, um Zootiere zu verwalten.
Dann hast du eine Oberklasse "Tier". Dabei fällt dir auf, daß du da
erstmal Unterklassen "Mensch" und "richtiges Tier" bilden kannst, weil
Menschen biologisch ja Tiere sind.
Menschen mußt du zwar nicht verwalten, aber so ist es "ordentlicher".
Einzeller hast du zwar im Zoo überall, aber verwalten mußt du die nicht.
Trotzdem, warum nicht in Ein- und Mehrzeller unterteilen?
Pilze sind zwar neben Pflanzen und Tieren ein eigenes Reich, aber
manchmal zählt man sie ja eher zu Tieren. Also nochmal Pilze aufnehmen.
All diese Klassen, die du für deine Anwendung nicht brauchst, kannst du
alle noch x-fach weiter unterteilen. Ist ja richtiger so.
Die werden zwar alle nie instantiiert werden, aber es ist doch schön,
die Welt korrekt abgebildet zu haben.
Erfahrene OOP-Entwickler machen solche Fehler natürlich nicht. Anfängern
passiert das aber ständig.
Deshalb nochamal: unterscheidet die Anwendung wirklich zwischen
verschiedenen Temperaturskalen, oder ist das nur, weils den inneren
Linnaeus befriedigt?
Mark 99 schrieb:> Beeep, beep, beep, Anti-OO Alarm.>> Ein gutes Objekt macht seinen internen Zustand nicht von Außen> erreichbar.
Ich denke du hast das mit dem internen Zustand falsch verstanden. Wenn
mir das Objekt weder Temperatur noch Einheit verrät, dann ist es nutzlos
;) Man muss die Getter/Setter ja nicht direkt auf die internen Variablen
setzen. Zusatzlogik (Prüfung ob neue Einheit gültig ist, automatische
Umrechnung der Temperatur, nicht weniger als absoluter Nullpunkt usw...)
kann man ja vorsehen, oder auch später bei Bedarf dazuprogrammieren.
Solange das alles über Getter/Setter läuft ist das kein Problem und auch
richtig gekapselt. Und kann problemlos erweitert werden.
> Deshalb nochamal: unterscheidet die Anwendung wirklich zwischen> verschiedenen Temperaturskalen, oder ist das nur, weils den inneren> Linnaeus befriedigt?
Jetzt leuchtet mir mehr ein, worauf die Aussage bezogen war. - Vielen
Dank ;-)
Nein, Celsius reicht eigentlich vollkommen aus.
Kevin schrieb:> Nein, Celsius reicht eigentlich vollkommen aus.
Was aber nicht heißt, dass es nicht trotzdem schlau wäre ein Objekt
daraus zu machen. Vererbung wird zwar meist als die primäre Nutzung von
OOP gelehrt, in der Realität ist das aber anders.
Gerade Kapselung ist sehr nett. Wenn du später einmal eine Überprüfung
des Wertebereichs hinzufügen möchtest, dann geht das total einfach wenn
die Temperatur ein Objekt ist.
Wenn du die Temperatur einfach als Variable "herumliegen" hast, dann
musst du die Logik überall vorsehen wo der Wert gesetzt wird, oder alle
diese Stellen auf eine Validierungsfunktion umbiegen.
Das hängt dann auch stark vom Projekt selbst ab was man als Objekt
modelliert und was nicht.
Jan Hansen schrieb:> Kevin schrieb:>> Nein, Celsius reicht eigentlich vollkommen aus.>> Was aber nicht heißt, dass es nicht trotzdem schlau wäre ein Objekt> daraus zu machen. Vererbung wird zwar meist als die primäre Nutzung von> OOP gelehrt, in der Realität ist das aber anders.>> Gerade Kapselung ist sehr nett. Wenn du später einmal eine Überprüfung> des Wertebereichs hinzufügen möchtest, dann geht das total einfach wenn> die Temperatur ein Objekt ist.>> Wenn du die Temperatur einfach als Variable "herumliegen" hast, dann> musst du die Logik überall vorsehen wo der Wert gesetzt wird, oder alle> diese Stellen auf eine Validierungsfunktion umbiegen.>> Das hängt dann auch stark vom Projekt selbst ab was man als Objekt> modelliert und was nicht.
Genau das war ja eigentlich meine Eingangsfrage. In wie weit macht es
Sinn die Klassen aufzuschlüsseln?
Kann man pauschal einfach sagen, dass man sich auf jeden Fall nach oben
immer eine Vererbungsklasse Luft lassen sollte? - wenn man das so sagt^^
Vererbung ist gerade DAS Element von OOP, was man nur sehr vorsichtig
einsetzen sollte. Wenn man große Vererbungshierarchien hat, sinkt die
Übersicht enorm, und es wird immer schwerer herauszufinden, was das
Programm da tatächlich eigentlich macht. Und jede Änderung an einer
Klasse in der Hierarchie hat das Potential, Fehler zu verursachen. Nicht
umsonst sagt man, dass Komposition der Vererbung vorzuziehen ist. Oft
ist es auch besser, ein paar Zeilen Code zu duplizieren, statt Vererbung
einzusetzen.
Komplexität ist i.A. das größte Problem bei Softwareentwürfen, daher
sollte man die Komplexität nicht noch künstlich erhöhen.
Kevin schrieb:> Genau das war ja eigentlich meine Eingangsfrage. In wie weit macht es> Sinn die Klassen aufzuschlüsseln?
Klein und fein ist schon in Ordnung. Nicht zu viel in eine Klasse
packen.
> Kann man pauschal einfach sagen, dass man sich auf jeden Fall nach oben> immer eine Vererbungsklasse Luft lassen sollte? - wenn man das so sagt^^
Das ist ein anderes Thema. Nein, ich würde da keine "Luft lassen"
(jemand weiter oben hat schon YAGNI genannt). Wenn du nur einen Sensor
hast und kein anderer dazukommt, dann genügt eine Klasse und du kannst
dir die Vererbung schenken. Wenn irgendwann einmal doch ein anderer
Sensortyp dazukommen würde, dann kannst du noch immer eine Superklasse
extrahieren und die jetzige davon ableiten. Da musst du nicht "auf
Vorrat" arbeiten. Keep it simple.
Jan Hansen schrieb:> Ich denke du hast das mit dem internen Zustand falsch verstanden. Wenn> mir das Objekt weder Temperatur noch Einheit verrät, dann ist es nutzlos> ;) Man muss die Getter/Setter ja nicht direkt auf die internen Variablen> setzen. Zusatzlogik (Prüfung ob neue Einheit gültig ist, automatische> Umrechnung der Temperatur, nicht weniger als absoluter Nullpunkt usw...)> kann man ja vorsehen, oder auch später bei Bedarf dazuprogrammieren.> Solange das alles über Getter/Setter läuft ist das kein Problem und auch> richtig gekapselt. Und kann problemlos erweitert werden.
Für alles Setter zu haben widerspricht der OO Natur, das macht man bei
Datenstrukturen, in Java wären das die JavaBeans ;)
Fowler nennt das "Anemic Domain Modell", führt dazu dass die Logik
woanders implementiert werden als dort wo doie eigentlichen Daten, so
wie man es vom Prozeduralen Ansatz her kennt.
Ansosnten gibt es einen grossen Unterschied zwischen "Encapsulation" und
"Information Hiding", wird oft durcheinander gewürfelt.
Wenn man mit einem Getter ein mutable Objekt zurückgibt, war es das mit
der Kapselung..
Kevin schrieb:> In wie weit organisiert man alles in Klassen?
Gar nicht.
Da du nur eine Instanz von Sensor und nur eine Instanz von Temperatur
haben wirst, sind Klassen absolut überflüssig.
Du wirst keinerlei objektorientierte Methode benötigen, wie Vererbung,
Polymorphismus, und keine Objekte anlegen und verwerfen auf dem uC.
Ein Programm ist dann optimal, wenn sich nichts mehr weglassen lässt,
ohne daß dann die Funktion nicht mehr erfüllt wäre, unter weglassen
versteht man die Maschineninstruktionen während der Abarbeitung, nicht
die Anzahl der Kommentare.
Zwar muss nicht jede Spielerei optimal werden, aber vorsätzlich den
entgegengesetzen Weg einzuschlagen ist schon sehr realitätsverweigernd.
MaWin schrieb:> Ein Programm ist dann optimal, wenn sich nichts mehr weglassen lässt,> ohne daß dann die Funktion nicht mehr erfüllt wäre, unter weglassen> versteht man die Maschineninstruktionen während der Abarbeitung, nicht> die Anzahl der Kommentare.
Na ja, das war vielleicht zu Zeiten der Lochkarten mal so.
In dem vorliegenden Fall ist ein Programm dann optimal, wenn es mit
möglichst wenig zusätzlichem Dokuemntationsaufwand leicht verständlich
und testbar formuliert ist.
Und ja, dabei helfen sinnvoll gestaltete Klassen ungemein.
Oliver
> einmal doch ein anderer Sensortyp dazukommen würde, dann kannst du> noch immer eine Superklasse extrahieren und die jetzige davon ableiten.
Das sehe ich eigentlich als den Hauptvorteil einer objekt basierten
Herangehensweise an: man kann auch im Nachhinein oft noch neue Klassen
einziehen, wenn sich die Forderungen im Programm verändern, ohne dass
gleich alles zusammenbricht.
Und ja. Ich hab in meinen OOP Anfängen auch genau den Fehler gemacht,
viel zu früh viel zu viel 'Flexibilität' in das Klassendesign auf Vorrat
einzubauen. Das Ergbnis war eine undurchschaubare Hierarchie, die zwar
im Prinzip alle möglichen Stückerl gespielt hätte ... wenn sie denn je
irgendjemand gebraucht hätte. Nach ein paar Jahren ist dieser Teil des
Programms (es ging um Operatoren in einem CAD Programm und wie
Mausmessages in diesem Konglomerat ihre Ergüsse an dieser Operatoren
weiter geben, die dann wieder über Zeichenklassen den Cursor bzw.
Hilfsgeometrie steuern) dann rausgeflogen und mit einem viel einfacheren
Mechanismus ersetzt worden, der dann auch wesentlich fehlerunanfälliger
war.
Klassenhierarchien muss man immer im Kontext der konkreten
Aufgabenstellung sehen. Was in der einen Aufgabenstellung sinnvoll ist,
muss in einer anderen Aufgabenstellung keineswegs sinnvoll sein
Oliver schrieb:> In dem vorliegenden Fall ist ein Programm dann optimal
Nein, optimal ist definiert, besuche eine Informatik-Vorlesung.
Du meinst vielleicht hübsch.
Aber hübsch liegt immer im Auge des Betrachters.
Kevin schrieb:> Muss ich also eine Klasse "Temperatur" anlegen? (hier könnte man ja> zwischen Fahrenheit und Celsius unterscheiden?
Wieso sollte man das tun? Deine Klasse (besser wäre sogar ein Interface)
Temperatur kapselt einfach einen Wert (z.B. double, int o.ä.) und stellt
einen Typ dar (am besten nicht veränderbar).
Außerdem hat sie einen Getter, welcher den Wert in der normierten
Einheit Kelvin zurückliefert. Eventuell hat sie noch Operatoren um
Temperaturen zu addieren/subtrahieren/serialisieren o.ä.
Wenn du nun aus irgendwelche Gründen in der Präsentationsschicht die
Ausgabe einer Temperatur in °Celsius oder °Fahrenheit benötigst dann
erstellst du dir einfach eine Formatierfunktion
Diese kann dann jedwede Temperatur in den gewünschten Ausgabewert
umwandeln.
Und dann ist es auch egal ob es genau EINE Temperatur Implementierung
gibt, oder eine SensorXYZTemperatur welche vielleicht immer live den
Wert abfragt wenn der getter aufgerufen wird... oder oder ...
Das muss man aber nicht zu dem Zeitpunkt entscheiden wo du die
Designentscheidung triffst "mein System hat den Typ Temperatur mit den
Eigenschaften....".
Kevin schrieb:> In wie weit organisiert man alles in Klassen?
Bjarne Stroustrup widmet gleich einen ganze Teil seines Buches ISBN
3-8273-1660-X (Abschnitt IV: Design Aspekte mit drei Abschnitten und
insgesamt 22 Kapiteln) dieser Frage. Ist zwar für C++, dürfte aber auf
C# übertragbar sein.
> Muss ich also eine Klasse "Temperatur" anlegen? (hier könnte man ja> zwischen Fahrenheit und Celsius unterscheiden?
In http://www.boost.org/ gibt es eine Unit-Library, die das Abbilden von
Einheiten ermöglicht. Ist sehr interessant, allerdings auch ein
ziemliches Monster und alles andere als einfach.
Läubi .. schrieb:> Deine Klasse (besser wäre sogar ein Interface)> Temperatur kapselt einfach einen Wert (z.B. double, int o.ä.) und stellt> einen Typ dar (am besten nicht veränderbar)
Ob mit oder ohne OO, verschiedene Temperaturen mitzuführen ist ohnehin
der völlig falsche Weg. Beispiel aus der CNC-Technik: die Steuerung
arbeitet grundsätzlich intern mit einer einzigen Masseinheit, z.B.
1/1000 mm. Inch kann man am Bildschirm sehen, wenn man denn will, oder
als Bearbeitungsprogramm einlesen, die Maschine weiss nichts davon.
Würde man die Positionieralgorithmen für verschiedene Masseinheiten
auslegen käme man in Teufels Küche, was Fehler angeht, und der Aufwand
ist auch völlig unnötig.
Eine Temperatur ist eine Temperatur ist eine Temperatur und sollte vom
absoluten Nullpunkt bis zu einer unereichbaren Obergrenze den
physikalischen Wert mit ausreichender Auflösung darstellen können, das
ist die primäre Designentscheidung. Ob sie in Kelvin, Celsius oder
Fahrenheit ein- oder ausgegeben wird ist eine Frage des User Interface
und nicht des Reglers.
Georg
Georg schrieb:> Würde man die Positionieralgorithmen für verschiedene Masseinheiten> auslegen käme man in Teufels Küche, was Fehler angeht
Das ist so nicht richtig.
Wenn das System inch als Koordinaten bekommt, und inch ausgeben soll,
treten wenn intern mit inch gerechnet wird keine Rundungsfehler auf, bei
mm schon.
Daher kann es sinnvoll sein, das zugrundliegende System umzuschalten,
machen beispielsweise manche Leiterplattenentwurfsprogramme so.
Bei CNC gibt es allerdings eine physikalische Auflösung der Achsen,
damit sind Rundungsfehler beim Abbilden auf Positionen nicht zu
vermeiden und es spricht nichts dagegen, mit denen zu rechnen.
Wenn man aber Schrittmotoren mit 64 Schritten pro Millimeter hat, ist es
blöd, erst die eingegebenen Koordinaten von inch in cm, und dann von cm
in Schritte umzurechnen, das ergibt bei Schrägen plötzlich
Streifenmuster an denen die Abbildung auf den nächsten Wert rundet, also
von abrunden auf aufrunden springt.
Kollege schrieb:> Für alles Setter zu haben widerspricht der OO Natur, das macht man bei> Datenstrukturen, in Java wären das die JavaBeans ;)
Gerade so ein einfaches Temperatur-Objekt ist doch ein perfektes
Beispiel für ein JavaBean ;)
> Fowler nennt das "Anemic Domain Modell", führt dazu dass die Logik> woanders implementiert werden als dort wo doie eigentlichen Daten, so> wie man es vom Prozeduralen Ansatz her kennt.
Ist ja grundsätzlich nicht schlecht. Und welche Logik möchtest du denn
bei einem simplen Temperatur-Objekt implementieren? Und warum kann man
keine Logik implementieren wenn man Getter/Setter verwendet?
> Ansosnten gibt es einen grossen Unterschied zwischen "Encapsulation" und> "Information Hiding", wird oft durcheinander gewürfelt.> Wenn man mit einem Getter ein mutable Objekt zurückgibt, war es das mit> der Kapselung..
Nein, wenn man aus dem internen Zustand ein neues mutable Objekt erzeugt
und das zurückgibt, dann ist das kein Problem.
Georg schrieb:> Würde man die Positionieralgorithmen für verschiedene Masseinheiten> auslegen käme man in Teufels Küche, was Fehler angeht, und der Aufwand> ist auch völlig unnötig.
Das Mitführen von Einheiten ist keinesfalls unsinnig, selbst wenn ich
nur eine Einheit pro Größe im System verwende. Es steht ja nirgends in
Stein gemeißelt, dass das immer so bleiben muss. Die oben zitierte
http://www.boost.org/ -Library beweist auch, dass das grundsätzlich
möglich ist, selbst ohne Laufzeit-Overhead.
> Eine Temperatur ist eine Temperatur ist eine Temperatur ...
Das hatten sich die Programmierer einer gewissen Mars-Sonde wohl auch
einst gedacht. Dumm nur, dass eine Temperatur – bzw. in diesem Fall war
es wohl eine Länge – in Amerika eben nicht gleich einer Temperatur in
Europa ist. Ergebnis: Totalverlust von hunderten Millionen Dollar. Wenn
das nicht Teufels Küche ist ...
Jan Hansen schrieb:> Gerade so ein einfaches Temperatur-Objekt ist doch ein perfektes> Beispiel für ein JavaBean ;)
Naja, so gesehen ist das ein ganz mieses Beispiel für Obekt als auch
Datenstruktur ;)
float/double oder gar int passen da viel besser..
Jan Hansen schrieb:> Ist ja grundsätzlich nicht schlecht. Und welche Logik möchtest du denn> bei einem simplen Temperatur-Objekt implementieren? Und warum kann man> keine Logik implementieren wenn man Getter/Setter verwendet?
"Nicht schlecht" sowieso, aber nicht OO!
Schon mal eine JavaBean mit Logik gesehen?
(Validierung zählt nicht)
Schon mal eine JavaBean gesehen die die per Repository/DAO die DB
abfragt?
"Das darf man nicht.." heisst es dann nicht ohne Grund, echte Objekte
dürften das.
http://www.martinfowler.com/bliki/AnemicDomainModel.html
Datenstrukturen wie JavaBeans leben eben davon, dass sie weder Kapselung
noch Information Hiding bieten, sind eben nur Datenstrukturen, oft als
DTO.
MaWin schrieb:> Wenn das System inch als Koordinaten bekommt, und inch ausgeben soll,> treten wenn intern mit inch gerechnet wird keine Rundungsfehler auf, bei> mm schon.
Das war vielleicht mal richtig. Rundungsfehler sind aber irrelevant,
wenn die rechnerische Auflösung deutlich höher ist als die mechanische -
ich habe vor 25 Jahren 32bit Integer verwendet mit der Einheit 1µ, das
hat Jahrzehnte ausgereicht, da die angeschlossenen Messmaschinen weniger
als 4m gemessen haben und nicht genauer als 1µ positioniert, allerdings
gibt es in Wirklichkeit schon Maschinen mit mehr als 4m und Messsysteme
besser als 1µ. Macht heute aber nix mehr, da 64 bit kein Problem mehr
ist, also kann man Nanometer auflösen und die Maschine kann so gross wie
die Erde sein. Wenn ich mich nicht verrechnet habe, aber in jedem Fall
langt es dicke und Runden ist kein Problem.
Georg
MaWin schrieb:> Daher kann es sinnvoll sein, das zugrundliegende System umzuschalten,> machen beispielsweise manche Leiterplattenentwurfsprogramme so.
Meines nicht. CadStar löst 10nm auf, und mir ist noch kein Teil
begegnet, bei dem Rundungsfehler eine Rolle gespielt hätten.
Georg
MaWin schrieb:> Oliver schrieb:> Nein, optimal ist definiert, besuche eine Informatik-Vorlesung.
Ja na, theoretisch optimal ist in den allermeisten Fällen praktisch
unbrauchbar.
Oliver
Oliver S. schrieb:>> Nein, optimal ist definiert, besuche eine Informatik-Vorlesung.>> Ja na, theoretisch optimal ist in den allermeisten Fällen praktisch> unbrauchbar.
Und genau das lernt man in besagter Informatik-Vorlesung. ;-)
Kollege schrieb:> Naja, so gesehen ist das ein ganz mieses Beispiel für Obekt als auch> Datenstruktur ;)> float/double oder gar int passen da viel besser..
Es geht aber um OO. Ja, ein primitiver Zahlentyp kann auch sinnvoll
sein, aber darum geht es hier nicht.
> "Nicht schlecht" sowieso, aber nicht OO!
Also für mich eindeutig schon OO. Warum denn nicht?
> Schon mal eine JavaBean mit Logik gesehen?> (Validierung zählt nicht)
Ja, Validierung ist auch Logik. Außerdem habe ich nicht mit den
JavaBeans angefangen, dass die per Definition eingeschränkt sind hat
nichts mit dem Thema zu tun.
> "Das darf man nicht.." heisst es dann nicht ohne Grund, echte Objekte> dürften das.
Reines Definitionsproblem. Und natürlich sind auch JavaBeans "echte"
Objekte.
Oliver S. schrieb:> Ja na, theoretisch optimal ist in den allermeisten Fällen praktisch> unbrauchbar.
Du meinst, praktisch kannst du es nicht und versuchst dich rauszureden.
Davon gibt es tausende.
Ne, es gibt tausende davon, die übersehen, daß ein optimales Programm
als allererstes einmal fehlerfrei sein muß. Nicht optimal, aber
fehlerfrei ist praktisch erheblich besser als gedacht optimal, mit
Absturz der Ariane als Folge...
O.iver
greg schrieb:> Komplexität ist i.A. das größte Problem bei Softwareentwürfen, daher> sollte man die Komplexität nicht noch künstlich erhöhen.
Das tut man aber, mit jeder neuen Hochsprache, jeder neuen Library,
immer neuen Erfindungen, Verfeinerungen und Konstrukten der OOP. Was von
der Intension her den Softwareentwurf vereinfachen sollte verkompliziert
ihn letztlich nur.
Kevin schrieb:> ein kleines Miniprojekt in C#
ist besser in wenigen Codezeilen erstellt die genau das tun was nötig
ist!
Und wenn wir hier nicht just in der Rubrik PC-Programmierung wären würde
ich sagen gleich in pure ASM.
Hier auch mal mein Senf dazu.
Gerade bei OOP ist viel Erfahrung nötig. Jahrelanges 'Spielen' ist da
angesagt. Dann bekommt man mit, wo es notwendig ist und wo man es
einfach beläst.
Mach am besten 2 Versionen. Ein mit viel und eine mit wenig OOP. Und
dann vergleiche mal die Vor- und Nachteile.
Bei einem anderen programm sieht das dann wieder ganz anders aus.
Zu den Einheiten. Ich mußte lange auch mit vielen physikalischen Größen
umgehen. Da habe ich mir angewöhnt, immer alles in SI-Einheiten
abzuspeichern. Da gab es dann nie die Frage, ob noch eine Kilo oder
micro davor gehört. Umgerechnet wurde nur bei Benutzer Ein/Ausgabe.
Programmintern war alles pure Meter.
PittyJ schrieb:> Gerade bei OOP ist viel Erfahrung nötig. Jahrelanges 'Spielen' ist da> angesagt.
Und genau deshalb ist OOP auch nicht der Weisheit letzter Schluß...
Oliver schrieb:> Endlich...> Da habe ich schon seit gefühlten 300 Beiträgen drauf gewartet.
Kann man nicht oft genug sagen.
PittyJ schrieb:> Mach am besten 2 Versionen. Ein mit viel und eine mit wenig OOP. Und> dann vergleiche mal die Vor- und Nachteile.
Bei so einem Micky Mouse Projekt kann OOP seine Vorteile doch gar nicht
ausspielen.
OOP kommt dann sinnvoll ins Spiel, wennn die Projektgrößen dergestalt
sind, dass sie von den Team-Mitgliedern Disziplin erfordern. In
klassischen prozeduralen Systemen (wie C) vertraut man darauf, dass die
Programmierer diese Disziplin haben, was oft genug in die Hose geht. In
OOP Sprachen (wie C++) hat man den Entwicklern Möglichkeiten in die Hand
gegeben, diese Disziplin einzufordern bzw. das System so aufzubauen,
dass es schwierig ist, am Gesamtkonzept vorbeizuprogrammieren und es
leicht ist, es in der Funktionalität zu erweitern.
Ja, bei kleinen Aufgabenstellungen sieht ein C++ Programm daher erst mal
völlig überkandidelt aus. Das liegt daran, dass im Vergleich zu rein
prozeduralen Ansätzen der Verwaltungsoverhead im Programmtext relativ
hoch ist. Aber das verliert sich mit wachsenden Projektgrößen.
> Gerade bei OOP ist viel Erfahrung nötig.
Ein gewisses Mass an 'Beamtenmentalität' ist da sehr hilfreich. Die
meisten vermurksten OOP Systeme, die ich bisher gesehen habe, drehten
sich praktisch immer um die Frage "Welche Klasse ist wofür zuständig",
bzw. eigentlich um das ignorieren dieser Fragestellung. Da wird dann auf
Teufel komm raus mit Gettern/Settern gearbeitet und Funktionalität
ausserhalb der zuständigen Klassen implementiert, die eigentlich ganz
klar in die Klasse rein gehören würde.
Jan Hansen schrieb:> Es geht aber um OO. Ja, ein primitiver Zahlentyp kann auch sinnvoll> sein, aber darum geht es hier nicht.
Dann sind JavaBeans so ganz falsch, den JavaBeans sind eben nicht OO,
steht schon in meinem letyzten Post warum und wieso, inkl. Link zur
einer ausführlichen Erklärung.
Jan Hansen schrieb:> Also für mich eindeutig schon OO. Warum denn nicht?
Hab ich doch eigentlich schon erklärt.
Jan Hansen schrieb:> Reines Definitionsproblem. Und natürlich sind auch JavaBeans "echte"> Objekte.
Eben nicht, aber auch das hatte ich schon erklärt.
auf die Gefahr hin, dass ich da nur noch in kaltem Kaffe rühre und alle
fragen geklärt sind:
Das schöne an OOP ist, es gibt so viele möglichkeiten das zum
implementieren, wobei flache hierachien meist sinnvoller sind.
Da OOP-Tutorials meist die Konzepte vermitteln wollen, haben die oft
irrsinnige Abstraktionstiefen.
Oft macht es mehr sinn helperfunktionen einfach static in einer
basisklasse unterzubringen, als noch eine noch vererbung mehr einzubaun.
Als gute Grundlage zu den DOs und DONTs kann man sich mal die Coding
guidelines des Qt-Projekts antun,
die sind nicht zu umfangreich, geben aber ein paar schöne Beispiele, was
sinnvoll ist, was weniger und warum welche Probleme in Qt wie gelöst
wurden.
Zurück zum Thema:
Wenn ich davon ausginge, dass es mal mehr als ein sensor und typ werden
könnten und dass ich vllt auch mal mehrere gleichzeitig haben will,
beides ist ja realistisch möglich, wäre mein konzept wohl wie folgt
Eine Baisklasse
class tempSensor
public
getValue(unit);
getUpdateRate() const;
setUpdateRate(int);
getType() const;
sowie
static convertUnit(value, fromUnit, toUnit);
convertUnit kann temperaturen von einheit a in einheit b umrechnen,
Dazu gibts dann eine Enum der gewünschten Temperaturskalen (Kelvin,
Celsius, Fahrenheit).
dem getter für die temperatur wird als standardwert für die einheit jene
zugewiesen, die ich primär nutzen will.
Ja, das könnte man als Klasse "temperatur" kapseln, halte ich aber nicht
für nötig, weil YAGNI halt.
Die Sensorklasse wird dann für jeden sensortyp abgeleitet, wenn ich
generische schnittstellen wie I2C oder sowas habe, die mehrere sensoren
nutzen könnten, wird das gekapselt. Der Konstruktor bekommt die nötigen
argumente um den sensor auszuwählen. Fertig die laube.
Jetzt kann man sich noch überlegen, ob die sensorklasse noch in der lage
sein soll, den sensor im hintergrund zu lesen oder whatever.
Klingt jetzt vllt nicht wie die hohe kunst der oop, halte ich aber für
angemessene abwägung zwischen struktur und simplicity.
Durch die Abstraktion des Temperatursensors als basisklasse kann es
meinem restlichen code wurst sein, was da später dran hängt.
Durch die static convertUnit kann ich temperaturen jederzeit in andere
einheiten umrechnen. Das Tracking der Temperatureinheit muss dann zwar
der den wert jeweils nutzende code machen, aber die umschaltung zwischen
den einheiten ist ja auch eher selten.
So ist es zum beispiel bei einer aufgezeichneten temperaturkurve nicht
sinnvoll, pro wert die einheit zu speichern, vielmehr werden wohl alle
messwerte die gleiche haben. Das ggf. nötige umrechnen kann der
anzeigende code machen mit tempSensor::convertUnit, wenns sein muss.
Karl Heinz schrieb:> OOP kommt dann sinnvoll ins Spiel, wennn die Projektgrößen dergestalt> sind, dass sie von den Team-Mitgliedern Disziplin erfordern.
Ach Karlheinz, DAS ist es eigentlich nicht.
Objektorientierte Programmierung hat genau dort ihren Sinn, wo mehrere
äußerlich gleichartig zu behandelnde, aber innerlich unterschiedliche
Objekte existieren. Ein typisches beispiel sind die diversen Kringel auf
einer grafischen Benutzeroberfläche.
Aber all das ist hier nicht der Fall. Der TO will einen Temperaursensor
auslesen und (vermutlich) dessen Temperaturwert auf irgend so einer
grafischen Oberfläche anzeigen. Wenn er dazu ne grafische
Klassenbibliothek benutzt, so hat es dort ganz gewiß genug passende
Objekttypen, die er benutzen kann.
Aber ne Klasse "Sensor" und ne klasse "Temperatur" ist schlichtweg
albern und unsachgemäß. Allein schon aus der logischen Erwägung heraus,
daß unterschiedliche Sensoren ja unterschiedliche Ergebnistypen liefern:
ein Thermometer liefert was anderes als ne Waage odeer ein Zollstock.
Die Ergebnisse sind nicht kommensurabel, also kann es keine
zusammenfassende Klasse für sowas geben.
Das Gegenteil liefert der Gedanke an eine Klasse "Temperatur". Hier ist
es nicht die inkommensurable vielfalt, sondern die öde Einfalt:
Temperaturen haben kein eigenes Innenleben, so daß man aus verschiedenen
Temperaturen eine Klasse bilden könnte. Das ist also auch völliger
Murks.
Oh ihr grandiosen Programmierer, lernt vor dem In_Die_Tasten_Hauen doch
um himmelswillen wenigstens ein klein wenig Logik. Das würde die Welt
verbessern.
W.S.
W.S. schrieb:> Das Gegenteil liefert der Gedanke an eine Klasse "Temperatur". Hier ist> es nicht die inkommensurable vielfalt, sondern die öde Einfalt:> Temperaturen haben kein eigenes Innenleben, so daß man aus verschiedenen> Temperaturen eine Klasse bilden könnte. Das ist also auch völliger> Murks.
Die Temperatur als Klasse zu modellieren ist sogar sehr sinnvoll. Eine
Temperatur hat einen (im Vergleich zu dem skalaren Typ int)
eingeschränkten Wertebereich. Wenn Du keinen eigenen Typ für die
Temperatur hast, müsstest Du korrekterweise bei jeder Zuweisung einen
Range-Check machen. Weiter macht es überaus Sinn, dass die
Temperaturklasse verschiedene Konvertierungen bietet, z.B. nach String,
...
Clean-Code Koriphäen wie Robert C. Martin empfehlen dringend für Domains
wie Währung, Geschwindigkeit, Temperatur, ... grundsätzlich eigene
Klassen zu verwenden. Das macht den Code erstens leserlicher und
zweitens leichter wartbar. Und das ist nicht nur bei großen Projekten
sinnvoll.
Aus eigener Erfahrung kann ich nur ins Feld führen, dass man irgendwann
mal klein beginnt (kleines Programm), sich die Dinge aber
unerwarteterweise plötzlich verselbständigen und schnell wachsen. Und
dann steht man vor einem Chaos-Haufen. :-(
Grüße
Markus
Hallo,
zusammen mit der "Erfindung" von OO kam eine Programmiersprache heraus,
deren Name mir entfallen ist (irgendwas mit A), die von extremen
Verfechtern der OO-Prinzipien konzipiert wurde. Die Sprache kannte keine
Zahlen, sogar ein Bit war eine Klasse - mit Setter, um es wahr oder
falsch zu setzen, getter, um es abzufragen, constructor, destructor
usw., und Methoden für and, or, xor...
Für mich kam das nicht in Frage, weil man sich den Aufwand im
Embedded-Bereich mit den damaligen Prozessoren der Z80-Klasse überhaupt
nicht leisten konnte. Ausserdem sehe ich das als fehlgeleitete
Ideologie, ich schreibe zwar seit 20 Jahren OO-Programme, aber ich
erwarte trotzdem, dass man 2 Ganzzahlen noch normal addieren kann.
Georg
W.S. schrieb:> Karl Heinz schrieb:>> OOP kommt dann sinnvoll ins Spiel, wennn die Projektgrößen dergestalt>> sind, dass sie von den Team-Mitgliedern Disziplin erfordern.>> Ach Karlheinz, DAS ist es eigentlich nicht.
Doch. Genau das ist es in der Praxis.
Ein 300 Zeilen Spaghetti Code Programm kann jeder überblicken. Auch noch
nach Jahren. NOch ein paar Nullen mehr hinten drann und dann geht das
nicht mehr.
OOP ist eine Methode, wie man Code strukturiert. Und das tut man, um den
Code wartbar zu halten.
> Objektorientierte Programmierung hat genau dort ihren Sinn, wo mehrere> äußerlich gleichartig zu behandelnde, aber innerlich unterschiedliche> Objekte existieren.
Natürlich. Keiner sagt, dass es nicht mehrere Motivationen für OOP geben
kann. Das eine schliesst das andere nicht aus. Und oft genug folgt das
eine aus dem anderen bzw. bedingt es.
Man kann auch mit C oder Fortran oder Pascal oder Algol oder Cobol oder
... riesige Systeme bauen. Das kann man und das wurde auch schon
gemacht. Wenn die Entwickler diszipliniert genug sind, sich an einfache
Prinzipien zu halten, dann ist das überhaupt kein Problem. Aber oft tun
sie das dann eben nicht. Anstatt eine Funktion aufzurufen, die einen
einfachen Sachverhalt berechnet, wird dann eben der Funktionsaufruf
eingespart und an der Aufrufstelle direkt gerechnet. Funktioniert super
... bis sich dann irgendwann mal die Berechnung ändert und man plötzlich
in der Situation ist, die 185 Stellen im Code zu finden, an denen die
Berechnung direkt gemacht wurde (weil man ja 'optimal' programmieren
will und ein Funktionsaufruf erst mal nur Zeit kostet) anstelle überall
die eine Funktion aufzurufen, die diese Berechnung durchführt.
Das meine ich mit Disziplin. C hat nichts zu diesem Thema zu sagen und
vertraut einfach darauf, dass die Programmierer das schon richtig
machen.
Been there - seen that - took a long time to correct it.
> lernt vor dem In_Die_Tasten_Hauen doch um himmelswillen wenigstens ein klein
wenig Logik.
Lern du erst mal, dass es in der Informatik nicht die eine, allein selig
machende, Methode gibt. Ob und wie ein Klassenaufbau sinnvoll aussieht,
hängt mehr als alles andere von der konkreten Aufgabenstellung ab.
> Aber ne Klasse "Sensor" und ne klasse "Temperatur" ist> schlichtweg albern und unsachgemäß.
Ach, ist es das?
> Allein schon aus> der logischen Erwägung heraus, daß unterschiedliche Sensoren ja> unterschiedliche Ergebnistypen liefern: ein Thermometer liefert> was anderes als ne Waage odeer ein Zollstock.
Und?
Warum kann es dann keine gemeinsame Basisklasse SensorWert geben, die
die Obermenge all dieser unterschiedlichen Werte darstellt? Wieso ist
das albern? Gerade in so einem Fall, in dem man diverse unterschiedliche
Typen unter einen Hut bringen möchte, ist das möglicherweise alles
andere als albern.
Wenn ich das brauche und sinnvoll nutzen kann, weil ich in meiner
Applikation in einem Grid die Bezeichnung des Wertes, den Wert selber
und seine Einheit darstellen muss UND ich die Dialogbehandlung
unabhängig von den tatsächlich möglichen Einheiten der diversen Werte
bzw. deren Typen haben will, dann ist so eine Basisklasse tatsächlich
sinnvoll. Oder was denkst du, wie in den diversen IDE's die Anzeigen für
die einzustellenden Properties eines Items in einem Resource Editor
realisiert ist? Riesige switch-case Strukturen?
Wieso soll ein geometrisches Item in einem CAD nicht eine PropertyList
liefern können, in der die diversen Properties dieses Items versammelt
sind, jedes nicht mehr als eine simple Einstellung (Breite, Höhe,
Winkel, Beschriftung, Farbe, Name, ...), die vom Anzeigemodul einfach in
der Form von Properties in die Controls eingebaut wird, indem zb jedes
Property aufgefodert wird, sich in die Zeile eines Grids reinzurendern?
Das kann sinnvoll sein. Hängt nur davon ab, welchen Aufwand ich treiben
muss bzw. will. Wer sagt eigentlich, dass ein Sensor nur einen einzigen
Wert liefert? Eine IMU liefert mehrere numerische Werte. Was ist mit
denen?
Genauso wie es nicht albern sein muss, unterschiedliche Sensoren unter
einer gemeinsamen Basisklasse Sensor in einer Hierarchie zu sammeln.
Wenn ich es sinnvoll nutzen kann, dann ist das alles andere als albern.
Die Aufgabenstellung bestimmt was sinnvoll ist und was nicht.
> Aber all das ist hier nicht der Fall. Der TO will einen Temperaursensor auslesen
Exakt. Und genau deshalb kann man an so einem Micky Mouse Beispiel nicht
sinnvoll festmachen, welche Vorteile OOP bringt. Diese Aufgabenstellung
(und ich rede hier nicht von der Klassenbibliothek zur Anzeige) kann
sowohl klassisch prozedural als auch mit OOP Methoden gelöst werden,
wobei der OOP Ansatz erst mal nach einem riesigen Overhead aussieht, den
keiner (in diesem Beispiel) braucht. Die Moral von der Geschichte ist
dann oft, dass die Leute sagen, dass OOP nichts bringt, weil ja das
gleichwertige C Programm um 2/3 kürzer und leichter zu überblicken ist -
in dieser konkreten Aufgabenstellung. Was OOP tatsächlich bringt und
leisten kann, sieht man erst in größeren komplexeren Systemen und das
auch erst dann, wenn man eine zeitlang damit gearbeitet hat. Für einen
OOP Neuling erschliesst sich der wesentliche Unterschied zwischen
hierarchischer Ableitung samt virtuellen Funktionen auf der einen Seite
und switch-case Leisten auf der anderen Seite nicht sofort. Für den ist
die switch-case basierend auf einer Typangabe erst mal einfacher, da
kürzer und weniger Tippaufwand. Das die auch fehleranfälliger ist, merkt
er erst, wenn er zum dritten mal damit auf die Nase gefallen ist, weil
er in einem der switches die Erweiterung um einen neuen Typ verpennt hat
und natürlich keinen assert im default hat.
Du warst doch der, der einem C-Programmierer Klassen und Ableitung (und
damit C++) nahegelegt hat, um auf einem µC mit Touchpad Bereiche
erkennen zu können. Dabei wollte der Fragesteller einfach nur simple
Rechtecke haben und nicht mehr. Jetzt wäre eine ähnlich simple
Aufgabenstellung (mit Potential für mehr) mit OOP Mitteln anzugehen
plötzlich albern. Bischen inkonsequent, findest du nicht?
Markus schrieb:> Aus eigener Erfahrung kann ich nur ins Feld führen, dass man irgendwann> mal klein beginnt (kleines Programm), sich die Dinge aber> unerwarteterweise plötzlich verselbständigen und schnell wachsen.
Aus meiner (begrenzten) Erfahrung ist genau da der Punkt, wo man
sinnvollerweise innehält und einen Schritt zurücktritt, um
Programmaufbau + Strukturen der neuen Komplexität anzupassen,
Basisklassen/Patterns einzuführen und alles soweit wie sinnvoll zu
abstrahieren. Code darf dabei auch gelöscht und allgemein neugeschrieben
werden.
Am Anfang mit einem Sensor und einem Fenster mit einer Zahl ist es zu
früh, weil man noch keinen Überblick hat, was gebraucht werden wird und
sich zwangsläufig irgendwelche Architekturen zusammenwasserfallt, die
später nicht funktionieren (alte Hasen ausgenommen).
Bei 20 verschiedenen Sensoren, die über UDP/RS232/GPIB/Brieftaube
ausgelesen und grafisch dargestellt werden, ist es zu spät, weil man
einen Haufen switch/case/if/else-Spaghetti hat.
Privat denkt man nicht immer rechtzeitig daran, weil das erstmal keinen
Spaß macht und keine sichtbaren Ergebnisse liefert; beruflich brüllt
einem vielleicht jemand ständig "Liefertermin! Das Zeug läuft, nicht
mehr anfassen, mach neue Features!" ins Ohr.
Tom K. schrieb:> Aus meiner (begrenzten) Erfahrung ist genau da der Punkt, wo man> sinnvollerweise innehält und einen Schritt zurücktritt, um> Programmaufbau + Strukturen der neuen Komplexität anzupassen,> Basisklassen/Patterns einzuführen und alles soweit wie sinnvoll zu> abstrahieren. Code darf dabei auch gelöscht und allgemein neugeschrieben> werden.
Kann ich unterschreiben. :-) Das Innehalten und Zurücktreten schaffen
aber leider die wenigsten. :-( Auch Profis nicht.
> Privat denkt man nicht immer rechtzeitig daran, weil das erstmal keinen> Spaß macht und keine sichtbaren Ergebnisse liefert; beruflich brüllt> einem vielleicht jemand ständig "Liefertermin! Das Zeug läuft, nicht> mehr anfassen, mach neue Features!" ins Ohr.
Privat ist es auch annähernd egal, wieviel Zeit man in die Wartung von
Spaghetticode steckt. Beruflich ist das von Dir beschriebene Verhalten
zwar gängige Praxis, aber leider sehr kurzsichtig.
In (Software-)Systemen, die über einen hinreichend langen Zeitraum
gepflegt werden müssen, ist dieser Ansatz (Liefertermin, keine Zeit)
langfristig das Todesurteil für das Produkt. Es ist recht schnell nicht
mehr mit vernünftigem Aufwand wartbar.
Grüße
Markus
Markus schrieb:> Die Temperatur als Klasse zu modellieren ist sogar sehr sinnvoll. Eine> Temperatur hat einen (im Vergleich zu dem skalaren Typ int)> eingeschränkten Wertebereich. Wenn Du keinen eigenen Typ für die> Temperatur hast, müsstest Du korrekterweise bei jeder Zuweisung einen> Range-Check machen. Weiter macht es überaus Sinn, dass die> Temperaturklasse verschiedene Konvertierungen bietet, z.B. nach String,
Das ist eine interessante Herangehensweise, die ich aber noch nirgends
live gesehen habe. Hast du da vielleicht ein Beispiel irgendeines
Open-Source-Projekts, wo das so gemacht wird?
Das Problem, das ich dabei sehe: Würde man das konsequent durchziehen,
müsste man ja für fast jede Variable eine eigene Klasse definieren, dazu
kommen dann noch unzählige Überladungen für die dafür benötigten
Rechenoperationen (vor allem Multiplikationen und Divisionen, bei denen
die beiden Operanden i.Allg. unterschiedliche physikalische Größen sind
und damit unterschiedlichen Klassen angehören).
Was ich mir in dieser Richtung ganz gut vorstellen kann, ist die
Verwendung unterschiedlicher Klassen abhängig von der Dimension der
jeweiligen physikalischen Größe, da dafür generische Klassen, wie sie
bspw. in der bereits angesprochenen Boost.Units-Bibliothek definiert
sind, verwendet werden können. Auch damit lassen sich schon sehr viele
Fehler in physikalischen Formeln aufdecken, und das sogar schon zur
Compile-Zeit. Nur hat man dort eben keine Überprüfung des Wertebereichs.
Yalu X. schrieb:> Das Problem, das ich dabei sehe: Würde man das konsequent durchziehen,> müsste man ja für fast jede Variable eine eigene Klasse definieren
Naja, für die Weltformel vielleicht. Für normale Projekte hat man doch
ein gewisses Domainmodel und da gibt es nicht so wahnsinnig viele
verschiedene Typen/Klassen.
Yalu X. schrieb:> dazu kommen dann noch unzählige Überladungen für die dafür benötigten> Rechenoperationen
Auch hier: Wie oft muss man JEDEN Typ mit JEDEM Multiplizieren, addieren
etc? Gerade die physikalischen Einheiten (wenn man nicht jenseits des
Teiches wohnt) sind doch überschaubar und wohldefiniert.
Ein Beispiel findest du hier für Messgrößen (incl. Fehlerabweichung):
http://www.osgi.org/javadoc/r4v42/org/osgi/util/measurement/package-summary.html
oder für Zeiteinheiten:
http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/TimeUnit.html
Es gibt nix blöderes als eine Funktion/Methode welche ein
long/double/... akzeptiert, der in Wirklichkeit aber ein Datum oder
Temperatur sein soll. Den da kommt man wirklich schnell hin, wenn viele
an dem Code arbeiten das dann jeder wie er lustig ist das interpretiert,
umrechnet und ausgibt, und ob der Wertebereich stimmt ist auch Fraglich.
Und wenn man das konsequent durchzieht, gibt es sehr wenig Stellen
(Erzeugung, Serialisierung) wo man tatsächlich sich um die internas
kümmern muss. Hat man dann noch das ganze interfacebasiert aufgebaut
kann man ein flexibles, wartbares und (modular) erweiterbares System
schaffen was Fehler von vornherein verhindert und auch noch gut Testbar
ist.
Karl Heinz schrieb:> Du warst doch der, der einem C-Programmierer Klassen und Ableitung (und> damit C++) nahegelegt hat, um auf einem µC mit Touchpad Bereiche> erkennen zu können.
Richtig. Ganz genau.
Aber siehst du denn nicht den logischen Unterschied?
Wenn du auf einem Bildschirm verschiedene grafische Elemente
unterschiedlicher Bauart hast, dann haben selbige zwar ein
unterschiedliches Innenleben, aber sie sind in mehreren entscheidenden
Punkten doch einheitlich: Sie haben alle irgendein Aussehen, was
gezeichnet werden muß. Sie haben zum Teil auch die Notwendigkeit, auf
Botschaften zu reagieren.
Sie stammen also im Prinzip alle von einem Ancestor ab, der prinzipiell
genau diese gleichen (virtuellen) Methoden hat: Darstellung und
Reaktion auf Ereignisse. Ihre vom übergeordneten System sichtbaren
Eigenschaften sind also kommensurabel (mit gleichem Maß meßbar und in
gleicher Weise behandelbar).
Bei solchen Dingen wie Sensor und Temperatur trifft das eben NICHT zu.
Ein Sensor liefert zwar im Allgemeinen eine Zahl, aber das ist eben
nicht einfach eine Zahl, sondern eine Größe also Zahl plus Maßeinheit.
Und deshalb sind unterschiedliche Sensoren eben NICHT kommensurabel. Sie
haben keinen gemeinsamen Ancestor. Das ist der grundlegende Unterschied
- ich hoffe, daß du das begreifst.
Bei der Temperatur sieht das zwar ganz anders aus, aber es ist auch
nicht besser: Eine Temperatur ist ein Zahlenwert plus eine Maßeinheit,
also eine Meßgröße. Daraus eine Klasse machen zu wollen, ist albern. Was
soll eine Klasse Temperatur denn bieten? Man kann ihr nichts zuweisen,
sie hat keine innere Struktur, sie ist eine Größe, die man messen und
zur Kenntnis nehmen kann - nicht mehr. Wer das nicht versteht wie Markus
kommt dann zu sowas:
Markus schrieb:> Die Temperatur als Klasse zu modellieren ist sogar sehr sinnvoll. Eine> Temperatur hat einen (im Vergleich zu dem skalaren Typ int)> eingeschränkten Wertebereich. Wenn Du keinen eigenen Typ für die> Temperatur hast, müsstest Du korrekterweise bei jeder Zuweisung einen> Range-Check machen. Weiter macht es überaus Sinn, dass die> Temperaturklasse verschiedene Konvertierungen bietet, z.B. nach String,
Der Range-Check ist Mumpitz, da man einer Temperatur nichts zuweisen
kann. Sie ist - für Programmierer - eine ReadOnly Sache. Man kann sie
mit einem Sensor erfassen (s.o.) und dessen Ergebnis zum Rechnen oder
schlichtweg zum Anzeigen verwenden - jedenfalls dessen numerischen Wert
unter Berücksichtigung der Maßeinheit - womit wir beim übergeordneten
Programm wären: Weder ein Sensor noch die von ihm gemessene Temperatur
können riechen, was mit ihrem Meßergebnis denn so geschehen soll. Das
ist Obliegenheit des Programmes, was das Meßergebnis verwendet und
dieses muß zwangsläufig Maßzahl und Maßeinheit bei der Verwendung
berücksichtigen. Sowas könnte weder ein Objekt "Sensor" noch ein Objekt
"Temperatur" leisten.
Ich nehme mal an, ihr meint etwas ganz anderes: nämlich visuelle Objekte
in einer grafischen Bibliothek, nennen wir sie mal TSensorDisplay und
TTemperaturAnzeige. Sowas kann selbstverständlich von einem Ancestor
TVisual abgeleitet werden wie z.B. TDropDown oder TButton. Sowas kann
auch auf Botschaften reagieren (neuer Wert eingetroffen) und es kann
sich zeichnen. Für sowas ist eine Klasse in Ordnung, wenn sie sich in
den Rest der verwendeten Bibliothek einordnet.
So, Leute, ich leg's euch ans Herz: Lernt das logische Denken und das
analytische Denken und das naturwissenschaftliche Denken. Im Moment
könnt ihr nur das Programmierer-Denken. Ist zwar auch was wert, reicht
aber nicht aus. Guckt über den Tellerrand.
W.S.
Wieso sollte eine Temperatur read-only sein müssen? Wenn ich eine
Heizung softwaretechnisch regeln möchte, kann ich sicherlich auch eine
Temperatur einstellen...
Allein schon die Möglichkeit, dass ich mir ein und dieselbe Temperatur
in verschiedenen Einheiten geben lassen möchte, bietet sich durch eine
Klasse an.
1
class Temperature
2
{
3
private decimal _valueInKelvin;
4
5
public decimal InKelvin { get { ... }; set { ... }; }
6
public decimal InCelsius { get { ... }; set { ... }; }
7
public decimal InFahrenheit { get { ... }; set { ... }; }
8
}
und so kann man auch mit Typen wie Länge, Fläche, usw. verfahren. Was
Sinn macht, nötig ist und gebraucht wird bestimmt immer die
Aufgabenstellung.
Obiges stammt sogar aus einem realen Industrieprojekt ;) Da liegen die
Typen die gebraucht werden im Domainmodel für alle Consumer verwendbar.
Egal ob ShowTemperatureView1 den Wert nun in K oder
DoSomethingWithTemperatureViewModelXY den Wert in °C braucht, das Model
kümmert sich drum.
Und es liest sich dann auch wie ein Roman:
1
if ( mySensorValue.InCelsius > 0 ) { ... }
besser als
1
// sensor value given in K, 273.15 is zero for celsius
2
if ( mySensorValue > 273.15 ) { ... }
Aber wie KH schon sagte, hängt viel davon ab bei welcher 10er-Potenz LOC
man sich im Projekt bewegt, 10^2 oder 10^6.
D. I. schrieb:> Wieso sollte eine Temperatur read-only sein müssen? Wenn ich eine> Heizung softwaretechnisch regeln möchte, kann ich sicherlich auch eine> Temperatur einstellen...
Weil es die Handhabung vereinfacht und "unerwartet" verhalten
eliminiert. Wenn du die Temperatur "ändern" willst, erzeugst du ein
Objekt mit der Wunschtemperatur und rufst z.B. setTemperatur(t) auf,
also alles kein Problem.
Der NUTZER einer Temperatur kann nun aber (da er weis das Objekt ändert
sich nicht mehr) genau dieses hernehmen, er kann es eventuell auch als
Identifikator für andere Werte hernehmen oder oder, ohne befürchten zu
müssen das "irgendwer" die inneren Werte des Temperaturobjektes ändert.
Kann er das NICHT müsste er streng genommen das Objekt jedesmal
kopieren, auch dürfte er sein inneres Objekt nicht ohne weiteres an
weitere an andere Funktionen weitergeben ohne es zu kopieren (der
aufgerufen würde es ggf. wieder kopieren und so fort...).
Auch hier gibt es garnicht so viele Fälle wo tatsächlich eine Temperatur
"erzeugt" oder "geändert" wird, dafür aber viele die die Temperatur
lesen und da die Temperatur nicht änderbar ist, kann ein
Temperaturobjekt problemlos geteilt werden, was auch die frage der
Synchronisation erheblich vereinfacht!
D. I. schrieb:> dass ich mir ein und dieselbe Temperatur in verschiedenen Einheiten> geben lassen möchte, bietet sich durch eine Klasse an
Nein, siehe mein Kommentar, so was gehört nicht in die Klasse/Interface!
Denn das Ergebnis ist nicht von (privaten) inneren Zuständen abhängig
sonder einzig und allein von den von außen zugreifbaren Werten, ene
"TmeperaturConversion" Klasse ist hier also sehr viel sinnvoller und
flexiebler falls morgen jemand eine Temperatur unbedingt als bytearray
oder oder oder benötigt...
D. I. schrieb:> Wieso sollte eine Temperatur read-only sein müssen? Wenn ich eine> Heizung softwaretechnisch regeln möchte, kann ich sicherlich auch eine> Temperatur einstellen...
Nein, das kannst du nicht. Stattdessen kannst du einem Regler einen
Sollwert vorgeben - das ist etwas anderes. Mag sein, daß du dafür das
Wort "Temperatur" benutzt, aber das ist unexakt.
Im Grunde hast du in deinem Beispiel eine Klasse TRegler, wo du einen
Sollwert vorgeben kannst, vllt. SollTemperatur genannt. Aber du hast
keine Klasse TTemperatur, die du einstellen kannst.
Allenfalls hast du in deiner Regler-Klasse eine readonly Property namens
MomentanTemperatur oder so ähnlich.
W.S.
W.S. schrieb:> Bei solchen Dingen wie Sensor und Temperatur trifft das eben NICHT zu.> Ein Sensor liefert zwar im Allgemeinen eine Zahl, aber das ist eben> nicht einfach eine Zahl, sondern eine Größe also Zahl plus Maßeinheit.> Und deshalb sind unterschiedliche Sensoren eben NICHT kommensurabel. Sie> haben keinen gemeinsamen Ancestor.
Darüber kann man jetzt lang und breit diskutieren, wie über alles andere
auch. Was ein Sensor ist, kann und darf sich jeder selber definieren,
und ob dann da eine Basisobjekt "Sensor" und davon abgeleitete
Spezifizierungen sinvoll sind, oder nur gemeinsame Interfaces, oder
sonst eine Lösung, ist nicht mit einem pauschalen Nein zu beantworten.
Aber im Fall des TO ist das ja alles auch sowieos völlig egal. Der will
EINEN Sensor auslesen. Ob das jetzt per OOP oder mit unabhängigen
Funktionen oder in Assembler oder optimal oder suboptimal oder sonstwie
gemacht wird, was solls.
Wenn da eine Bedienoberfläche in C# für Windows dazu kommt, wird die
sowieso 99% des Programmumfangs umfassen, und Struktur und Ablauf des
Programms objektorientiert vorgeben. Ob die Sensorbehandlung dann auch
in eine eigene Klasse wandert, oder nicht, ist völlig nebensächlich.
Oliver
W.S. schrieb:> Ein Sensor liefert zwar im Allgemeinen eine Zahl, aber das ist eben> nicht einfach eine Zahl, sondern eine Größe also Zahl plus Maßeinheit.
Man könnte es auch MESSWERT nennen (Zahl+Fehler+Einheit), das ist doch
etwas was allen Sensoren eigen ist.
> Bei der Temperatur sieht das zwar ganz anders aus, aber es ist auch> nicht besser: Eine Temperatur ist ein Zahlenwert plus eine Maßeinheit,> also eine Meßgröße. Daraus eine Klasse machen zu wollen, ist albern. Was> soll eine Klasse Temperatur denn bieten? Man kann ihr nichts zuweisen,> sie hat keine innere Struktur, sie ist eine Größe, die man messen und> zur Kenntnis nehmen kann - nicht mehr.
Sehe ich nicht so, wenn ich eine Temperatur haben will, dann will ich
eine Temperatur und kein beliebeigen double in Kilogram. Also wieso
nicht temperatur von der generischen Klasse/Interface 'Meßgröße' welche
ein double und eine Einheit liefert ableiten? Wer mit allgemeinen
'Meßgrößen' arbeiten kann kann diese ja nutzen, wer explizit wenigstens
eine Temperatur benötigt kann dies in seiner Methode dokumentieren und
der Compiler kann das im Vorfeld prüfen.
Hier in "nicht-klassen-würdige" Objekte unterscheiden zu wollen ist
nicht zielführend. Ob eine direkte VERERBUNG Sinn macht ist ein ganz
andere Punkt, ich habe ja schon oben geschrieben, das man sowas eher
interface-basiert machen sollte, und die entscheidung ob Vererbung oder
nicht der implementierung überlassen.
Hallo,
nach der (angeblich erstrebenswerten) MVC-Architektur
(Model-View-Controller) gehören Umrechnungen der internen Temperatur in
Fahrenheit, Reaumur oder sonstwas eindeutig nicht zum Model, sondern zum
View (Ausgabe) oder Controller (Eingabe). Was der intern verwendete Wert
darstellt, z.B. float Kelvin, müssen natürlich alle Beteiligten wissen!
Es wäre ja absurd, wenn ein Temperaturregler mit einer anderen internen
Grösse arbeiten würde, nur weil das Gerät nach Frankreich oder USA
geliefert wird. Auch darf eine Erweiterung der Software um weitere
provinzielle Masseinheiten überhaupt keinen Einfluss auf die Regelung
haben.
Georg
Läubi .. schrieb:> D. I. schrieb:>> Wieso sollte eine Temperatur read-only sein müssen? Wenn ich eine>> Heizung softwaretechnisch regeln möchte, kann ich sicherlich auch eine>> Temperatur einstellen...>> Weil es die Handhabung vereinfacht und "unerwartet" verhalten> eliminiert. Wenn du die Temperatur "ändern" willst, erzeugst du ein> Objekt mit der Wunschtemperatur und rufst z.B. setTemperatur(t) auf,> also alles kein Problem
... mh könnte meinen Vorschlag auch als struct realisieren und es
kombinieren mit deinem:
Regler.setTemperature(Temperature t)
@MVC: Umrechnungnen sehe ich sehr wohl als Model-Logik, die View
entscheidet lediglich was sie darstellen möchte. Maximal noch im
Controller, aber bei MVC greift im Zweifel die Faustregel "thin
controllers, fat models".
Läubi .. schrieb:> Sehe ich nicht so, wenn ich eine Temperatur haben will, dann will ich> eine Temperatur und kein beliebeigen double in Kilogram. Also wieso> nicht temperatur von der generischen Klasse/Interface 'Meßgröße' welche> ein double und eine Einheit liefert ableiten?
Wozu, wozu, WOZUHUHUHUHU bloß?
Als akademische Programmierer-Übung ohne Realitätsbezug?
Als Selbstverwirrung?
Kommt demnächst ein Programmierer auf die Idee, einem TKörper eine
TMasse zuweisen zu wollen? Nun, die Schönheitsindustrie würde das ja
begrüßen, man könnte damit sich selbst sein Idealgewicht zuweisen, auch
dann, wenn man nicht ißt sondern frißt. Die Damen werden es den
Programmierern danken.
Ich hab das hier grad anderswo zitiert (aus dem Stroustrup): "Language
shapes the way we think, and determines what we can think about"
Ihr habt offensichtlich schon zuviel C++ verinnerlicht, so daß ihr aus
dieser Denke nicht mehr herauskommt und den Wald vor Bäumen nicht mehr
seht.
Läubi .. schrieb:> wer explizit wenigstens> eine Temperatur benötigt kann dies in seiner Methode dokumentieren
Ja, eben: An was für eine Methode hast du denn bei einer Temperatur
gedacht? Ist es überhaupt denkbar, daß ein physikalischer Meßwert
eingebaute Methoden oder Properties hat (eben außer seinem tatsächlichen
Wert)? Nein, natürlich nicht.
Das äußerste, was hier in Programmiererkreisen denkbar ist, ist eine
API-Funktion des Betriebssystems, mittels derer man eine Aussage über
eine Temperatur erfragen kann (Beispiel: aktuelle CPU-Temperatur). Das
gibt ne Zahl und die Maßeinheit liest man in der BS-Doku nach. Wo
bittesehr siehst du hier eine auch nur ansatzweise Möglichkeit,
irgendwelche Methoden unterzubringen?
Läubi .. schrieb:> Sehe ich nicht so, wenn ich eine Temperatur haben will, dann will ich> eine Temperatur und kein beliebeigen double in Kilogram.
Nee, du kriegst vom BS eine Zahl und was die bedeutet - siehe oben.
Mehr ist nicht drin in der Tüte.
Jetzt kannst du dich natürlich hinsetzen und dir sagen: "Ich bau mir da
jetzt ne Breitseite von allem ein, was mir grad einfällt und dann hab
ich Methoden und Properties bis zum Abwinken." Aber wo bleibt da der
eigentliche Sinn bei der derart kreierten TYaluTemperaturClass?
W.S.
Zumindest dauert es jetzt 5 Tage, und bis sich die Experten über eine
korrekte TemperaturKlasse einig sein werden scher noch mal 5 Monate, und
innerhalb von 5 Minuten hätte man das Programm ohne OOP fertig
geschrieben.
Das kostet dann ein tausendstel (Aufwand, Geld), aber OOP ist ja SOOO
arbeitssparend.
Und nach 5 Monaten stellt dann die versammelte Programmierertruppe fest,
daß der erzeugte Code leider nicht in den Programmspeicher des
anvisierten Microcontroller passt, weswegen ein redesign mit refactornig
für eine leightweight TemperaturKlasse notwendig ist, nicht ohne externe
Beratung einzuholen obwohl man doch beratungsresistent ist.
Die Branche ist so verkotzt inzwischen.
D. I. schrieb:> Nein, du bist nur in den 70ern stehen geblieben..
nanananana..
Ständig nur beleidigt (und dann beleidigend) zu reagieren, wenn die
Argumente ausgehen und dann zu schreiben "du hast ja keine Ahnung" oder
"du bist ja sooo doof" usw. hilft niemendem.
Es legt auch beredtes Zeugnis ab davon, daß der Schreiber am Verstehen
der ihm nicht schmeckenden Argumente gescheitert ist, aber seinen zu
kleinen Horizont einfach nicht zugeben will.
W.S.
W.S. schrieb:> Es legt auch beredtes Zeugnis ab davon, daß der Schreiber am Verstehen> der ihm nicht schmeckenden Argumente gescheitert ist, aber seinen zu> kleinen Horizont einfach nicht zugeben will.
MaWin mag von Elektrotechnik große Ahnung haben, aber sein
Softwarehorizont reicht nicht über 100 Zeilen Mikrocontroller hinaus,
das hatten wir im Forum aber schon gefühlte 1000 mal. Da gibts mit KH,
Läubi, Yalu etc. andere Kompetenzen.
Natürlich kann man immer erstmal was zusammenhacken was irgendwie tut,
so siehts dann hinterher auch aus und so wartbar isses dann auch. Btw.
MaWin sollte der letzte sein, der sich darüber beschweren kann in einem
ranzigen Ton angeredet zu werden.
Edit: Du hast auch auch keine sonderlich ernstzunehmende Argumente
gebracht, deswegen lohnt es sich nicht mit euch beiden weiter über
dieses Thema zu diskutieren.
Andreas Lang schrieb:> [...] Die Sensorklasse wird dann für jeden sensortyp abgeleitet, wenn ich [...]
Hier vermengst du doch Hardware mit Software.
Klasse Temperatur sollte sich nur um solche kümmern.
Dieser Teil ist Applikationsspezifisch komplett hardwareunabhängig.
Genauso wie es eine I²C Klasse geben sollte, die sich nur um die
Ansteuerung der Schnittstelle kümmert und der egal ist, was mit den
geholten Daten passiert, oder wie sie zu interpretieren sind.
Der Teil ist natürlich hardwareab- aber anwendungunabhängig. Klassischer
Treibersoftware halt.
Dazwischen sitzt eine Ebene, HAL (Hardware Abstraction Layer) genannt,
die deine konkrete Application an die Hardware koppelt. Sie sagt dem I²C
"hol die Daten" und rechet sie (bestenfalls in SI-Einheiten) um und
übergibt sie der Applikation.
Das ganze ist unabhängig von Programmiersprache oder OOP oder Nicht-OOP.
Gehst du auf eine neue Hardware musst du nur passende Treiber suchen und
den HAL anpassen. Bringst du eine andere Anwendung auf die bekannte
Hardware, musst du nur den HAL anpassen. Schreibst du eine neue
Anwendung für eine neue Hardware musst du halt alle drei Komponenten
schreiben, aber meist finden sich zumindest Treiber schon irgendwo.
Bastelst du ein µC Projekt, wo abzusehen ist, dass du die Hardware das
erste und letzte mal siehst und das nicht sehr komplex ist und nicht
gewartet werden soll, vermischt man halt Application und HAL. Treiber
würd ich trotzdem immer extra halten.
Kevin schrieb:> In wie weit organisiert man alles in Klassen?
Nun, Kevin - wie du hier lebhaft sehen kannst, ist es am Besten, du
findest deinen eigenen Weg. Probiere aus, betrachte deine Loesungen
selbstkritisch, verbessere sie. Schau hin und wieder ueber den
Tellerrand und lasse dich inspirieren. Aber auf keinen Fall solltest du
dir etwas von anderen Vorbeten lassen oder irgendwelchen Goetzen
nacheifern.
Finde deinen Weg.
D. I. schrieb:> Nein, du bist nur in den 70ern stehen geblieben und bist wahrscheinlich> frustriert weil du nicht mithalten konntest.
Im Gegensatz zu dir ist mein Programm schon längst fertig und verkauft
sich prächtig und bringt Millionen ein.
Dein Geschwätz hingengen ist sachlich falsch, und das weiss ich,
deutlich besser als du, denn du redest über mich.
Und so weiß ich auch vieles andere deutlich besser als du.
D. I. schrieb:> Du hast auch auch keine sonderlich ernstzunehmende Argumente> gebracht
Hast du irgend etwas Ernstzunehmendes dagegen zu setzen?
Nein?
Hast du wenigstens eine Ergänzung, eine Weiterführung, eine Präzisierung
- kurzum irgend etwas Sachliches dazu zu sagen?
Auch nein?
Dann laß solche Bemerkungen und gehe das nächste Mal wenigstens ein
wenig auf das ein, was ich geschrieben habe.
Wie gesagt: einfach bloß "du bist ja doof" zu schreiben reicht einfach
nicht aus. Gilt auch für dich.
W.S.
MaWin schrieb:> schon längst fertig und verkauft> sich prächtig und bringt Millionen ein.
Und warum fängst du dann hier im Forum einen blödsinnigen Streit nach
dem anderen an, statt dich in St. Tropez auf deiner Yacht zu sonnen?
Georg
Quack schrieb:> Kevin schrieb:>> In wie weit organisiert man alles in Klassen?>> Nun, Kevin - wie du hier lebhaft sehen kannst, ist es am Besten, du> findest deinen eigenen Weg. Probiere aus, betrachte deine Loesungen> selbstkritisch, verbessere sie. Schau hin und wieder ueber den> Tellerrand und lasse dich inspirieren. Aber auf keinen Fall solltest du> dir etwas von anderen Vorbeten lassen oder irgendwelchen Goetzen> nacheifern.>> Finde deinen Weg.
Vielen Dank für deine Einschätzung. Aktuell sieht es ja so aus, als wenn
das sowieso jeder völlig anders angehen würde.
Gruß,
Kevin
Es wird immer Leute geben, die alles Neue verteufeln und mit dem Alten
"Millionen verdienen". Das ist ja nicht schlimm. Wenns so funktioniert,
ist ja gut.
Tragisch ist nur, wenn das für sie Neue schon bald fünfzig Jahre alt
ist. eg
Fred schrieb:> Tragisch ist nur, wenn das für sie Neue schon bald fünfzig Jahre alt> ist. eg
Und selbst wenns 200 wären...
Eine gute Lösung bleibt eine gute Lösung. Insbesondere wenn sie einfach
ist. Das "Neue" gibts leider oft nur im Bundle mit mehr, nur allzuoft
unnötiger Komplexität.
Kevin schrieb:> Vielen Dank für deine Einschätzung. Aktuell sieht es ja so aus, als wenn> das sowieso jeder völlig anders angehen würde
Da gibts eben die OOP Theologen, deren Lösung schön komplex sein muß,
damit dieses Blendwerk ordentlich was hermacht und solche, die nur und
genau das programmieren, was der Problemstellung tatsächlich angemessen
ist.
Naja, kommen wir mal zum eigentlichen Kern der Sache zurück:
Kevin schrieb:> Muss ich also eine Klasse "Temperatur" anlegen? (hier könnte man ja> zwischen Fahrenheit und Celsius unterscheiden?>> Außerdem muss ich ja sicher eine Klasse Sensor anlegen. Wie weit würde> man das ganze noch aufdroeseln?
Es kommt drauf an, was du willst:
a) üben, wie man ne Klasse anlegt?
b) auf deinem PC auf der grafischen Oberfläche ein Fenster haben, wo dir
die aktuelle Temperatur entgegengrinst?
c) auf deinem PC ein Tool haben, also ein biederes
Kommandozeilenprogramm von stdin nach stdout, oder den aktuellen
Temperaturwert in eine Datei schreiben?
d) der Frage nachgehen, was man sinnvoll in C++ oder auch in anderen
Sprachen, die OOP bieten, in Objekte quetscht oder eben auch nicht?
Ganz allgemein sag ich dazu, daß es zu allererst nötig ist, sich mit
sich selber über die Begrifflichkeiten ins Klare zu kommen: Eine Klasse
"Temperatur" ist albern, eine Klasse "Temperatur_Adapter" oder
"Temperatur_Anzeiger" oder "Temperatur_Regler" hingegen nicht. es kommt
auf den beabsichtigten Inhalt an, also was da innerhalb des Objektes
'leben' soll. Für ein stupides 'double' wäre eine eigene Klasse
übertrieben bis zur Albernheit, für z.B. einen PID-Regler hingegen sieht
das völlig anders aus.
W.S.
Moby schrieb:> solche, die nur und> genau das programmieren, was der Problemstellung tatsächlich angemessen> ist.
Ich stelle mir gerade so vor, wie dich beim Einstellungsgespräch der
Personalchef fragt, ob du Erfahrungen mit OO hast, und du antwortest
"ich programmiere nur das, was der Problemstellung tatsächlich
angemessen ist"...
Ich habe ja weiter oben das Beispiel gebracht mit einer Klasse Bit mit
Getter/Setter für true und false und Methoden für and, or, xor, sowas
macht einfach viel mehr her. War übrigens keine Fantasie von mir, das
gibt es wirklich, sogar als verbindliche Lösung. Die Sprache hiess
Actor, von Whitewater.
Georg
Georg schrieb:> Ich stelle mir gerade so vor, wie dich beim Einstellungsgespräch der> Personalchef fragt...
Der fragt aber nicht, Georg. Als Bastler hat man eben den einzigartigen
Luxus, sich auf das tatsächlich notwendige beschränken zu können :-)
W.S. schrieb:> übertrieben bis zur Albernheit
Genau das ist OOP- zumindest für alle jene Millionen Problemstellungen,
die nicht über ein bestimmtes Maß an Komplexität hinausgehen. Hinter der
softwaretechnisch eleganten Anmutung steckt allein unnötiger Overhead
und Dokumentationsbedarf. Aber schee schauts aus- und trefflich
akademisch diskutieren lässt sich darüber auch.
Moby schrieb:> unnötiger Overhead
Ich habe mal versucht mich zu erinnern wie man OO-mässig addiert:
aus der Gleichung
s = x + y
die man in "normalen" Programmiersprechen genauso eingibt, wird bei
Actor:
s.SetValue (x.AddValue (Y.GetValue));
supereindrucksvoll und sooo übersichtlich, nicht?
Georg
Georg schrieb:> Ich habe mal versucht mich zu erinnern wie man OO-mässig addiert:>> aus der Gleichung> s = x + y> die man in "normalen" Programmiersprechen genauso eingibt, wird bei> Actor:>> s.SetValue (x.AddValue (Y.GetValue));>> supereindrucksvoll und sooo übersichtlich, nicht?
Ich kenne Actor nicht, aber scheint ja eine reichlich antiquierte
Sprache zu sein. Kein Wunder, dass du da keinen Spaß daran hattest.
Außerdem ist das was du hier machst nicht wirklich der OO-Weg. Wenn ich
mit objektorientiert-funktionalem Denken Assembler programmiere, kann
ich auch nicht einfach Zeile für Zeile übersetzen.
Zu deinem Beispiel: sollte man das wirklich so brauchen, dann gibt es
dafür im Normalfall Operatorüberladung und primitive Typen. Dann bleibt
es auch bei s = x + y.
Je nach Aufgabenstellung hat man aber oft andere Fälle, z.B. addiere
eine Länge zu einer anderen Länge:
s = x.add(y)
Das ist, finde ich, schon ganz nett. Sobald x und y nicht mehr die
gleiche Einheit haben kann man die Umrechnung schön in der Add-Methode
kapseln. Und wenn ich mich vertippe und zur Länge eine Temperatur
addieren möchte schreit der Compiler.
Moby schrieb:> und solche, die nur und> genau das programmieren, was der Problemstellung tatsächlich angemessen> ist.
Genau die, die immer nur das programmieren, was der Aufgabenstellung
angemessen ist, haben überhaupt zur Entwicklung der höheren
Programmiersprachen und danach zu deren Weiterentwicklung geführt.
Warum wohl nur?
Oliver
Peter schrieb:> Schon mal von Operatorüberladung gehört?Jan Hansen schrieb:> dann gibt es> dafür im Normalfall Operatorüberladung und primitive Typen.
Da habt ihr garnichts verstanden. Actor war als streng OO konzipiert,
d.h. Operatoren gibt es nicht. Punkt. Das hätten die Erfinder als
Rückfall in die Primitivität abgelehnt (wie Jan sagt: primitive Typen.
Die gab es natürlich ebensowenig wie Operatoren). Ausserdem wäre das ja
inkonsequent: wenn man z.B. integer mit dem Operator + addieren kann,
wozu muss ein integer dann noch ein Objekt einer Klasse sein? Was soll
denn vererbt werden, wenn nicht Methoden wie Add?
Actor wurde gleich nach den ersten Erwähnungen von OO als die ultimative
Lösung mit vollständiger Umsetzung des OO-Gedankens propagiert, ist aber
bald in der Versenkung verschwunden. Nach meiner Ansicht zu Recht, und
das sollte mein Beipiel begründen. Ich würde das als fundamentalistische
OO bezeichnen.
Georg
Georg schrieb:> Da habt ihr garnichts verstanden. Actor war als streng OO konzipiert,> d.h. Operatoren gibt es nicht. Punkt.
Warum widerspricht die Verwendung von Operatoren dem objektorientierten
Programmierparadigma?
Falls dich der Bergiff "Operator" stört: Benenne ihn einfach um, bspw.
in "Methode mit 1 Argument" (wie in C++) oder "binäre Nachricht" (wie in
Smalltalk).
Falls dich die Schreibweise mittels Sonderzeichen ('+'. '-' usw.) stört:
Das ist ausschließlich eine Frage der Syntax, nicht des Paradigmas.
> Ich würde das als fundamentalistische OO bezeichnen.
Wenn allgemein anerkannte und der Lesbarkeit dienende syntaktische
Konstrukte wie die Infixnotation arithmetischer Ausdrücke sinnloserweise
einem übertriebenen OO-Wahn geopfert werden, würde ich das schon eher
als extremistische OO bezeichnen ;-)
Yalu X. schrieb:> Falls dich die Schreibweise mittels Sonderzeichen ('+'. '-' usw.) stört:> Das ist ausschließlich eine Frage der Syntax, nicht des Paradigmas.
Das ist mir schon klar, dass das alles geht und auch gehen sollte, aber
die damaligen Macher haben das im Interesse der reinen Lehre eben nicht
vorgesehen. Könnte man die Addition mit + schreiben, wäre der
beabsichtigte erzieherische Effekt hin zu OO ja nicht mehr gegeben
gewesen. Aber lassen wir solche Verirrungen in Frieden ruhen, ausser mir
erinnert sich sowieso keiner mehr an Actor (immerhin findet Google noch
was).
Georg
Georg schrieb:> Aber lassen wir solche Verirrungen in Frieden ruhen, ausser mir> erinnert sich sowieso keiner mehr an Actor (immerhin findet Google noch> was).
Die Frage ist, warum du diese "Verirrung" dann gegen OO in Stellung
bringst.
Vielleicht solltest du dir eine modernere Sprache ansehen - vielleicht
wirst du ja noch ein Fan :)
Oliver S. schrieb:> Genau die, die immer nur das programmieren, was der Aufgabenstellung> angemessen ist, haben überhaupt zur Entwicklung der höheren> Programmiersprachen und danach zu deren Weiterentwicklung geführt.
Für komplexe Problemstellungen braucht es sicher neue Herangehensweisen.
OOP ist ein mehr oder weniger gelungener Versuch dazu.
Die Problemstellung des TO gehört wie Millionen andere sicher nicht
dazu. OOP ist eben KEIN passendes Universalwerkzeug für alle Fälle.
Aber wer einen tollen Hammer in der Hand zu halten glaubt neigt
natürlich dazu, in jedem Problem einen Nagel zu sehen ;-)
Der Begriff "Einfachheit" hat im übrigen auch etwas doppelbödiges an
sich. Der sich entwickelnde Profi wird darunter etwas anderes verstehen
als der Bastelamateur. Laufend werden Programmiersprachen
weiterentwickelt und um neue Konstrukte erweitert, die dem Profi im
konkreten Fall Vereinfachung versprechen, das ganze System aber
letztlich aufblasen und dann doch immer komplizierter = lernintensiver
machen. Egal. Wenn irgendwann kaum einer mehr einsteigt ist jedes System
sowieso zum Untergang verurteilt.
Georg schrieb:> im Interesse der reinen Lehre...
und nach strikten pauschalen Regularien / Programmierideologien wird man
selten zur passgenauen, einfachsten Lösung finden.
Moby schrieb:> OOP ist ein mehr oder weniger gelungener Versuch dazu.> Die Problemstellung des TO gehört wie Millionen andere sicher nicht> dazu.
Der TO programmiert aus Spaß, hat bisher keine Erfahrung mit OOP, und
möchte da einfach mal Erfahrung sammeln. Das macht das mir einer
einfachen Anwendung. Ist doch völlig in Ordnung. Ja, das Problem lässt
sich (als Konsolenanwendung) mit ein paar Zeilen Assembler erschlagen,
aber darum geht es doch gar nicht.
Oliver
Kevin schrieb:> Muss ich also eine Klasse "Temperatur" anlegen? (hier könnte man ja> zwischen Fahrenheit und Celsius unterscheiden?
Eine Klasse "Temperatur" ergibt generell wenig bis gar keinen Sinn.
Genau so, wie eine Klasse "Zeit" oder "Länge" oder "Stromstärke" oder
"Volumen" wenig bis gar keinen Sinn ergibt.
Physikalische Größen wird man in der OOP in aller Regel als eine
"hat-ein" Beziehung antreffen. Also:
-ein Fahrzeug hat eine Geschwindigkeit v
-ein Gegenstand hat eine Masse m
-ein Temperatursensor hat einen Temperaturwert ϑ (Theta)
Eine "hat-ein" Beziehung wird man in den Member-Variablen wiederfinden,
über die eine Klasse verfügt. Und in den Methoden, die darauf operieren.
> Außerdem muss ich ja sicher eine Klasse Sensor anlegen. Wie weit würde> man das ganze noch aufdroeseln?
Man kann eine Basisklasse "Sensor" anlegen, von der man dann alle
anderen Sensoren ableitet. Das ist im Gegensatz zu oben eine "ist-ein"
Beziehung. Die "ist-ein" Beziehung findet sich in der Klassenhierarchie
wieder. Also:
-ein Temperatursensor ist ein Sensor
-ein Helligkeitssensor ist ein Sensor
-ein Feuchtigkeitssensor ist ein Sensor
und so weiter. Zu Übungszwecken: Warum nicht. In einer realen Anwendung
auf einem Mikrocontroller, auf dem überhaupt nur ein einziger Sensor
existiert: Unnötiger Mehraufwand. In einem Projekt, in dem es eine
Vielzahl von unterschiedlichen Sensoren gibt: Kann sinnvoll sein. Ob es
das ist oder nicht, hängt immer von der konkreten Aufgabenstellung ab.
Mark Brandis schrieb:> Geschwindigkeit
Eine Geschwindigkeit hat einen Numerischen Wert und eine Einheit
> Masse
Eine Masse hat einen Numerischen Wert und eine Einheit
> Temperaturwert
Ein Temperaturwert hat...
Also wieso sollten diese nicht (von der gemeinsamen Basisklasse
Messgröße) abgeleitete konkrete Klassen sein?
Ob etwas "Sinn hat" ergibt sich nicht aus der Sache sondern aus dem
Kontext. Ein µC mit 2x16 LCD für die Anzeige der Raumtemperatur hat ganz
andere Anforderungen als eine Simmulationssoftware für Wetterphänomene.
Läubi .. schrieb:> Ein Temperaturwert hat...
Ja, aber die Masseinheit mitzuführen ist unsinnig. Wann immer ich mit
Temperaturen zu tun habe, verwende ich die absolute Temperatur in
Kelvin, es gibt einfach keinen vernünftigen Grund, mit etwas anderem zu
rechnen. Also brauche ich auch keine Eigenschaft Masseinheit, sondern
nur den Zahlenwert.
Noch krasser bei CAD-Systemen: alle mir bekannten Systeme haben eine
interne Masseinheit, z.B. nm. Alle linearen Masse haben diese Auflösung,
es wäre daher völlig unsinnig, bei z.B. Tausenden von Pin-Positionen auf
einer Leiterplatte bei jeder einzelnen die Tatsache mitzuspeichern, dass
es sich um nm handelt. Auf dem Bildschirm wird sowieso zwischen einer
ganzen Reihe von Einheiten umgeschaltet, da ist die Anzeigesoftware für
die Umrechnung zuständig.
Falls man das überhaupt je braucht, kann man im Handbuch nachlesen, was
die native Einheit des Systems ist. Natürlich kann ein Idiot etwas
falsch interpretieren, aber gegen Idioten hilft auch OO nicht, die muss
man halt vom Programmieren fernhalten.
Ich weiss schon, dass es heute absolut uncool ist, Speicherplatz zu
sparen, aber deswegen muss man ihn ja nicht vollkommen sinnlos
einsetzen.
Georg
Georg schrieb:> Ich weiss schon, dass es heute absolut uncool ist, Speicherplatz zu> sparen,
und Rechenleistung noch dazu. Die Hardware muß immer fetter werden um
die zunehmend ineffiziente Programmierung auszugleichen. Bis nix mehr
geht und ein Systemwechsel unausweichlich wird ;-(
Läubi .. schrieb:> Mark Brandis schrieb:>> Geschwindigkeit>> Eine Geschwindigkeit hat einen Numerischen Wert und eine Einheit>>> Masse>> Eine Masse hat einen Numerischen Wert und eine Einheit>>> Temperaturwert>> Ein Temperaturwert hat...>> Also wieso sollten diese nicht (von der gemeinsamen Basisklasse> Messgröße) abgeleitete konkrete Klassen sein?
Kann man machen, aber was genau bringt das?
Intern wird man für gleiche physikalische Größen auch mit der gleichen
Skalierung rechnen. Von daher sehe ich es so wie Georg, die Einheit wird
für die Berechnungen an sich nicht als eine Eigenschaft in einer Klasse
mit abgespeichert. Ein Meter pro Sekunde ist dann intern in einer
Variablen nicht als ein Zahlenwert 1 gespeichert, sondern vielleicht als
10 oder 100 oder 1000. Also skaliert, damit man in Integer-Arithmetik
mit ganzen Zahlen auch (sehr) kleine Geschwindgkeiten ausdrücken kann.
Anders mag es bei der GUI aussehen. Hier stellt man vielleicht in
Kilometern pro Stunde dar, was intern mit skalierten Metern pro Sekunde
gerechnet wird. Das ist aber ein Problem der Anzeige, keines der
Berechnung. Rechnen wird man alles in der gleichen, vorher festgelegten
Skalierung, weil es anders wenig sinnvoll wäre.
Läubi .. schrieb:> Ein µC mit 2x16 LCD für die Anzeige der Raumtemperatur hat ganz> andere Anforderungen als eine Simmulationssoftware für Wetterphänomene.
Selbst bei Letzterer würde es mich wundern, wenn sowohl
Windgeschwindigkeit als auch Niederschlagsmenge als auch Luftdruck als
auch Temperatur alle von der gleichen Basisklasse abgeleitet sind. Falls
es doch so ist, lasse ich mich gerne eines Besseren belehren.
Mark Brandis schrieb:> Kann man machen, aber was genau bringt das?
Weniger nötiges Spezialwissen
(http://de.wikipedia.org/wiki/Truck_Number), (Dein Beispiel zeigt es
doch gut, "vielleicht skaliert", "vielleicht 10, 100, 1000"... was
interessiert die interne Repräsentation?), Flexibilität (Was wenn in
Zukunft eben NICHT ein Zahlenwert ausreicht, sondern noch eine
Fehlerabweichung benötigt wird?), Generische Methoden (ja, man kann auch
mit Einheiten rechnen), Typsicherheit (Eine Temperatur ist keine
Geschwindigkeit oder Gewicht oder Zeit...), Dokumentation (was soll ich
100 Zeilen Kommentar verfassen wenn es ein vernünftiger Typ tut um
auszudrücken was Sache ist).
Warum sollte ich all das verschenken (zumal der Aufwand minimal ist),
und stattdessen darauf bauen das ich nächstes Jahr (oder mein Kollege
morgen) noch weiß welche "ist-doch-alles-klar"-Annahmen ich getroffen
habe.
Ich habe ja oben schon ein Beispiel verlinkt wo es konkret um Messwerte
geht, mit denen man auch rechnen kann, und die sogar den Messfehler
berücksichtigen.
Mark Brandis schrieb:> Rechnen wird man alles in der gleichen, vorher festgelegten Skalierung,> weil es anders wenig sinnvoll wäre
Auch das muss nicht sein (und ist eher einschränkend) da die zu
verwendende Genauigkeit ggf. einstellbar oder sogar dynamisch ist. Man
sollte sich auch nicht zu arg an den Berechnungen festkrallen, diese
sind in den meisten Programmen nicht der Hauptbestandteil oder gerade
dort eher generischer Natur.
Ansonsten wird hier immer schön argumentiert das es "keinen Vernünftigen
Grund" für irgendwas gäbe, Argumente hört man leider keine.
Läubi .. schrieb:> Ansonsten wird hier immer schön argumentiert das es "keinen Vernünftigen> Grund" für irgendwas gäbe, Argumente hört man leider keine.
Ich denke mal das liegt einfach daran, dass viele Entwickler dafür weder
im Studium noch im Berufsleben jemals ein Beispiel gesehen haben. Das
heißt nicht, dass es keines gibt. Wenn es eines gibt, dann zeig doch
bitte mal konkreten Code. Auszugsweise und beispielhaft reicht.
Mark Brandis schrieb:> Ich denke mal das liegt einfach daran, dass viele Entwickler dafür weder> im Studium noch im Berufsleben jemals ein Beispiel gesehen haben.
Das heißt aber auch nicht, dass es nicht sinnvoll ist, nur weil viele es
nicht schaffen, sinnvolle Konzepte umzusetzen und lieber "business as
usual" betreiben, weil wir das ja immer schon so gemacht haben.
Domainspezifische Klassen wie Temperatur, Masse, ... haben den Vorteil,
dass man damit typsicheren Code schreibt. Jeden Fehler, den der Compiler
findet, führt nicht zu einem Laufzeitfehler beim Kunden. Wobei das bei
"Bastelprojekten" natürlich irrelevant ist.
Grüße
Markus
Läubi .. schrieb:> Ansonsten wird hier immer schön argumentiert das es "keinen Vernünftigen> Grund" für irgendwas gäbe, Argumente hört man leider keine.
Dass es völlig unsinniger Aufwand ist, bei einer Leiterplatte mit 20000
Bohrungen zu jeder einzelnen Bohrung ein Objekt zu speichern statt
einfach die X/Y-Koordinaten, ist für dich also kein Argument? 40000 mal
die überflüssige Information, dass die Koordinaten in nm sind? Sowas ist
bloss gut, um damit anzugeben, aber Lichtjahre von der Praxis entfernt.
Natürlich ist meine Meinung für dich völlig irrelevant, aber
komischerweise arbeiten reale CAD-Systeme so, ganz ohne mich gefragt zu
haben. Wahrscheinlich haben sie einfach den natürlich unverzeihlichen
Fehler gemacht, DICH nicht zu fragen. Allerdings müssten wir dann wohl
immer noch auf CAD-Systeme warten, die auf einem normalen PC laufen.
Georg
Georg schrieb:> 40000 mal> die überflüssige Information, dass die Koordinaten in nm sind?
Offensichtlich fehlt es Dir an der nötigen Abstraktionsfähigkeit. Wo
steht denn geschrieben, dass man beim Modellieren einer entsprechenden
Klasse immer eine (konstante) Einheit mit ablegt. Jeder (halbwegs)
vernünftige Entwickler käme wohl von alleine auf die Idee, dass diese
Information redundant sein könnte und deshalb einfach implizit im
Klassendesign enthalten ist.
Und ganz ehlich: 40000 Objekte? Lächerlich! Wir sind heute nicht mehr in
den Zeiten von C64 und Co., wo man mit jedem Bit rumgeizt (zumindest
solange man sich nicht im embedded Bereich bewegt). Speicherplatz sparen
ist sicherlich ganz nett, aber "Optimierungen" bringt man da an, wo es
anfängt eng zu werden. Wesentlich wichtiger ist eine saubere
Modellierung, sei es objektorientiert, prozedural oder sonst irgendwie.
Grüße
Markus
Markus schrieb:> Domainspezifische Klassen wie Temperatur, Masse, ... haben den Vorteil,> dass man damit typsicheren Code schreibt.Markus schrieb:> Wesentlich wichtiger ist eine saubere> Modellierung, sei es objektorientiert, prozedural oder sonst irgendwie.
Schon recht. Nur wenn ich prozedural in C programmiere, habe ich halt
keine Klassen. Viele Embedded-Projekte zur Steuerung von Maschinen,
Anlagen, Fahrzeugen etc. sind nun mal in C geschrieben. Da gibt es dann
halt keinen Prozesswert "Temperatur", der von einer Basisklasse
"Messwert" abgeleitet ist.
Georg schrieb:> Dass es völlig unsinniger Aufwand ist, bei einer Leiterplatte mit 20000> Bohrungen zu jeder einzelnen Bohrung ein Objekt zu speichern statt> einfach die X/Y-Koordinaten, ist für dich also kein Argument? 40000 mal> die überflüssige Information, dass die Koordinaten in nm sind? Sowas ist> bloss gut, um damit anzugeben, aber Lichtjahre von der Praxis entfernt.
Mein 3 Jahre altes "Smartphone" hat einen Duo Core Prozessor mit mind.
1GHz Takt, dazu 16GiB RAM.
40000 Referenzen auf ein Immutable Objekt sind da gar kein Problem oder
Faktor.
Was war nochmal mit der "Premature Optimization", diesem Spruch aus den
70'er Jahren? ;)
Markus schrieb:> Wo> steht denn geschrieben, dass man beim Modellieren einer entsprechenden> Klasse immer eine (konstante) Einheit mit ablegt
Das hat Läubi höchstselbst als der Weisheit letzten Schluss und als
zwingenden Grund für eine Klasse propagiert:
Läubi .. schrieb:> Eine Geschwindigkeit hat einen Numerischen Wert und eine Einheit
Aber wie schon Adenauer (oder wars Strauss) sagte, was geht mich mein
dummes Geschwätz von vorgestern an.
Georg
Kolllege schrieb:> Mein 3 Jahre altes "Smartphone" hat einen Duo Core Prozessor mit mind.> 1GHz Takt, dazu 16GiB RAM.
Beim RAM hast du dich wahrscheinlich um den Faktor 16 vertan. Sollte
aber trotzdem kein Problem sein.
Georg schrieb:> Das hat Läubi höchstselbst als der Weisheit letzten Schluss und als> zwingenden Grund für eine Klasse propagiert:>> Läubi .. schrieb:>> Eine Geschwindigkeit hat einen Numerischen Wert und eine Einheit
Er hat aber NICHT geschrieben, dass jedes Objekt die Einheit
mitschleifen muss, oder? Das ist nämlich ausschließlich Deine
Interpretation. ;-) Seine Aussage läßt durchaus zu, dass die
Geschwindigkeits- oder auch die Temperaturklasse die Einheit implizit
enthält.
Grüße
Markus
Markus schrieb:> Er hat aber NICHT geschrieben, dass jedes Objekt die Einheit> mitschleifen muss, oder? Das ist nämlich ausschließlich Deine> Interpretation. ;-) Seine Aussage läßt durchaus zu, dass die> Geschwindigkeits- oder auch die Temperaturklasse die Einheit implizit> enthält.
Was ist dann der Unterschied zu einer Variablen? Wenn ich Variablen zum
Beispiel so benenne:
Battery_voltage
Vehicle_velocity
Converter_temperature
dann dürfte wohl klar sein, dass die Einheiten nicht Sekunde, Ampere und
Watt sind.
Jan Hansen schrieb:> Beim RAM hast du dich wahrscheinlich um den Faktor 16 vertan. Sollte> aber trotzdem kein Problem sein.
Tatsache, meinte natürlich die SD Karte mit 16GiB, Ram hat es "nur"
1GiB, ist ja auch schon "alt" ;)
Ansonsten finde ich es etwas schwer pro oder contra zu argumentieren
wenn man den Kontext nicht kennt.
OOP auf einem Mikrocontroller?
Nun, der MC muss schon recht groß sein..
Assembler auf einem x86 um ein CRM zu implementieren?
Nun, da muss jemandem recht langweilig sein um so ein Unterfangen zu
starten..
"Einheiten", mit oder ohne?
Je nachdem.. in OOP Sprachen würde ich eher mit "Ja" stimmen, als
Immutable implementieren (in Java gar als Enum), dann reicht ein
einziges Einheiten Objekt pro konkreter Einheit.
meckert der Compiler (wenngleich die Fehlermeldung schon etwas länglich
und nicht sehr aufschlussreich ist). Auf jeden Fall lassen sich damit
aber einige Fehler zur Compilezeit aufdecken, die ansonsten – wenn
überhaupt – erst zur Laufzeit zutage treten würden. Da die Überprüfung
komplett zur Compilezeit erfolgt, beinhalten die drei verwendeten
Variablen keinerlei Information über Größe, Dimension oder Einheit. Jede
von ihnen ist nur so groß wie der zugrundeliegende numerische Datentyp
(in diesem Fall double). Der Speicherverbrauch kann also kein Argument
gegen den Einsatz dieser Bibliothek sein.
Insofern ist die Boost.Units schon eine sehr feine Sache.
Das Ganze geht aber nur deswegen so leicht von der Hand, weil die Boost
alle dazu benötigten Hilfsmittel bereits fertig zur Verfügung stellt.
Würde man hingegen, wie hier von einigen propagiert, eigene Klassen
für Weg, Geschwindigkeit und Beschleunigung schreiben, wäre das selbst
in diesem primitiven Beispiel schon mit recht hohem Aufwand verbunden.
In Java, das kein Operator-Overloading kennt, würde die obige Formel
zudem ziemlich unleserlich werden.
Ich kann mir deswegen kaum vorstellen, dass sich jemand in realen
Anwendungen tatsächlich diese Mühe macht. Selbst fertige Bibliotheken,
wie die Boost.Units oder die org.osgi.util.measurement, die die
dimensionssichere Programmierung mit wenig Zusatzaufwand erlauben
würden, scheinen von von den wenigsten Programmierern genutzt zu werden.
Stattdessen werden in geschätzten 99,9% der Fälle für physikalische
Größen ganz klassisch dimensionslose Doubles ohne jegliche
Überprüfungsmöglichkeit durch den Compiler oder das Laufzeitsystem
verwendet.
>Insofern ist die Boost.Units schon eine sehr feine Sache.
Danke für den Hinweis.
Yalu X. schrieb:> Selbst fertige Bibliotheken,> wie die Boost.Units [...] scheinen von von den wenigsten Programmierern genutzt
zu werden.
könnte an
> wenngleich die Fehlermeldung schon etwas länglich> und nicht sehr aufschlussreich ist
liegen. Ohne zwingenden Grund will sich niemand der
Templatefehlermeldungshölle ausliefern. In der Zeit, die man braucht, um
aus dem ganz simplen Beispiel im Anhang -- Dein Beispiel geändert auf
das falsche v=sqrt(2*g)*h -- herauszufinden, dass irgendein Fehler in
Zeile 17 ist, hat man schon einen Unittest geschrieben.
Tom schrieb:> Beispiel im Anhang -- Dein Beispiel geändert
Nachtrag: Der Anhang ist für einen anderen Fehler als beschrieben, die
Meldung sieht aber ziemlich gleich aus: 12kB Müll für "In Zeile 17
passen die Einheiten nicht."
Tom schrieb:> Tom schrieb:>> Beispiel im Anhang -- Dein Beispiel geändert> Nachtrag: Der Anhang ist für einen anderen Fehler als beschrieben, die> Meldung sieht aber ziemlich gleich aus: 12kB Müll für "In Zeile 17> passen die Einheiten nicht."
Zugegeben, lesbar ist das nicht. Aber wenigstens merke ich, dass in
Zeile 17 ein Fehler steckt, und zwar schon während des Compilierens und
nicht erst, wenn die millionenschwere Raumsonde den halben Weg zum Mars
bereits hinter sich hat...
Yalu X. schrieb:> Stattdessen werden in geschätzten 99,9% der Fälle für physikalische> Größen ganz klassisch dimensionslose Doubles ohne jegliche> Überprüfungsmöglichkeit durch den Compiler oder das Laufzeitsystem> verwendet.
Ich kenne da aus der beruflichen Praxis eher Integer (Stichwort
Festkommaarithmetik) als Gleitkommazahlen, aber der Grundaussage stimme
ich zu.
Das wird sich im übrigen genau dann ändern, sobald ein solches Feature
komfortabel zu benutzen ist und man nicht kryptischen Fehlermeldungen
hinterherjagen muss. Solange wird es nämlich kaum jemand freiwillig
nutzen wollen. Programmierer sind so. ;-)
Ach ja, und der zweite Grund dafür, dass das kaum jemand macht ist dass
das Projektmanagement kein Geld dafür herausrückt. Niemand wird
Hunderttausende Zeilen an bestehendem und funktionierendem Code mal eben
verboostisieren.
Wenn man etwas von Grund auf neu entwickeln würde, dann wäre das schon
eine gute Sache. Aber wie oft entwickelt man in einem realen
Industrieprojekt die Dinge von Grund auf neu? Ganz genau. Meistens
arbeitet man ja doch an etwas bereits Bestehendem und baut eine neue
Funktionalität ein.
A. H. schrieb:> Zugegeben, lesbar ist das nicht. Aber wenigstens merke ich, dass in> Zeile 17 ein Fehler steckt, und zwar schon während des Compilierens und> nicht erst, wenn die millionenschwere Raumsonde den halben Weg zum Mars> bereits hinter sich hat...
Dazwischen sollten freilich noch ein paar Tests liegen. Wäre auch zu
schön, wenn ein fehlerfrei kompilierendes Programm auch ein fehlerfreies
wäre.
Mark Brandis schrieb:> Dazwischen sollten freilich noch ein paar Tests liegen. Wäre auch zu> schön, wenn ein fehlerfrei kompilierendes Programm auch ein fehlerfreies> wäre.
Stimmt natürlich. Mindestens genauso schön wäre es aber auch, wenn eine
(vermeintlich) fehlerfrei getestetes Programm tatsächlich fehlerfrei
wäre. Tests können die Fehlerfreiheit eine Programms bekanntlich auch
nicht beweisen.
Übrigens, wer immer noch glaubt, Einheiten seien überflüssiger
Schnickschnack, der lese zum Beispiel mal hier nach:
http://de.wikipedia.org/wiki/Mars_Climate_Orbiter
Mark Brandis schrieb:> Das wird sich im übrigen genau dann ändern, sobald ein solches Feature> komfortabel zu benutzen ist und man nicht kryptischen Fehlermeldungen> hinterherjagen muss. Solange wird es nämlich kaum jemand freiwillig> nutzen wollen. Programmierer sind so. ;-)
Ist es nicht eher so, dass kaum jemand die kryptischen Fehlermeldungen
zu Gesicht bekommen hat, weil er sich die Boost.Units-Bibliothek gar
nicht erst angeschaut hat? ;-)
> Ach ja, und der zweite Grund dafür, dass das kaum jemand macht ist dass> das Projektmanagement kein Geld dafür herausrückt. Niemand wird> Hunderttausende Zeilen an bestehendem und funktionierendem Code mal eben> verboostisieren.
Man muss bestehenden und funktionierenden Code nicht nachträglich
verboostisieren. Da der Code ja schon getestet ist, sollte er keine
groben Fehler mehr enthalten. Deswegen ist es ausreichend, in seinen
Schnittstellen nach außen dimensionsbehaftete Typen zu verwenden.
Noch etwas zu den kryptischen Fehlermeldungen:
F# unterstützt Maßeinheiten schon in der Kernsprache, was dem Compiler
ermöglicht, wesentlich aussagekräftigere Fehlermeldungen zu generieren.
Hier ist das obige Beispiel in F#:
1
[<Measure>] type m
2
[<Measure>] type s
3
4
let fallhoehe = 3.00<m>
5
let erdbeschleunigung = 9.81<m/s^2>
6
7
let geschwindigkeit:float<m/s> = sqrt (2.0 * fallhoehe * erdbeschleunigung)
In Zeile 7 wird geschwindigkeit explizit als float<m/s> deklariert,
wodurch der Compiler mögliche Dimensionsfehler im Ausdruck rechts des
Gleichheitszeichens erkennen kann.
Ändert man diese Zeile in
1
let geschwindigkeit:float<m/s> = sqrt (2.0 * fallhoehe / erdbeschleunigung)
meldet der Compiler
1
test.fs(7,58): error FS0001: The unit of measure 'm/s' does not match the unit of measure 's'
was ganz klar auf die Fehlerursache hinweist.
Es ist schade, dass nur die allerwenigsten Programmiersprachen von Hause
aus über solche Features verfügen. Außer in F# habe ich das nur noch in
Fortress gesehen, dessen Entwicklung aber leider vor ein paar Jahren
eingestellt worden zu sein scheint.
A. H. schrieb:> Übrigens, wer immer noch glaubt, Einheiten seien überflüssiger> Schnickschnack, der lese zum Beispiel mal hier nach:>> http://de.wikipedia.org/wiki/Mars_Climate_Orbiter
War das nicht im Pflichtenheft drin gestanden, dass man mit den
richtigen SI-Einheiten rechnen muss und nicht mit dem Ami-Quatsch? ;-)
Mark Brandis schrieb:> War das nicht im Pflichtenheft drin gestanden, dass man mit den> richtigen SI-Einheiten rechnen muss und nicht mit dem Ami-Quatsch? ;-)
Die Amerikaner können sich einfach nicht vorstellen, dass es ausserhalb
ihres Landes auch andere Masseinheiten gibt. Dem kann man aber mit OO
auch nicht beikommen, denn dazu müsste man dort einen Tankinhalt ja mit
x Gallonen definieren, wofür ein US-Ingenieur aber garkeinen Grund
sieht, weil man das ja immer in Gallonen misst. Das ist wie beim
ASCII-Code: mehr Buchstaben als A..Z braucht niemand. Die spinnen die
Europäer mit ihren Umlauten.
Georg