Hallo!
Statement:="Entschuldigung!", Reciever:="Michael"
Akzeptiert. Zumal sie mit benannten PARAMETERN daherkommt.
Im Gegenzug bekommst Du daher von mir an dieser Stelle das
Bekenntnis: Autodidakten sind sexy. ;-)
<Paul>
Post by Michael ZimmermannAber warum in aller Welt müssen sie <Objekte>
generisch sein?
<Michael>
Post by Michael ZimmermannDiese Forderung hat wenig mit Objekt oder nicht Objekt
zu tun. Ich würde auch im rein prozeduralen Bereich
erwarten, daß eine Funktion mindestens zu einem
gewissen Grad über Parameter an verschiedene
Anwendungsumgebungen angepaßt werden kann.
Also z. B. statt eines Function-Stapels
HoleKundeVorname, HoleKundeNachname,
HoleLieferantVorname, HoleLieferantVorname, ... eine
HoleWert(Entität, Attribut)
Führt das nicht dazu, dass man ganz viel mit Variants und
all den damit verbundenen Fehlern klar kommen muss?
Natürlich ist Generalisierung nicht das einzige, worauf
man zu achten hat, und wenn Interessenkonflikte mit
gegenläufigen Prinzipien entstehen, muß man einen sinnvollen
Kompromiß finden.
Vererbung ist da ein sehr elegantes Prinzip, da man
gleichzeitig extrem abstrakte Basisklassen, die kaum
noch semantischen Gehalt haben, mit diese involvierenden
spezialisierten Klassen kombinieren kann. Das ist für
mich einer der wertvollsten Aspekte der Programmierung
mit Klassen, daß man so scheinbar unvereinbare Forderungen
unter einen Hut bringen kann.
Auch für die Lesbarkeit ist ein sprechender Prozedurname,
doch allemal besser als so allgemeine Funktionen wie
"HoleWert"...
Nichts gegen lesbaren Code. Aber ein gewisses geistiges
Niveau darf man bei Programmierern doch voraussetzen.
Wenn einer beim Anblick harmloser Parameter schon
Hautausschlag bekäme, würde ich eine so mathematik-
und logiklastige Tätigkeit wie Programmieren als falsche
Berufswahl ansehen.
Ja, und dann kommen später die optionalen
Parameter und VBs "geniale Auto-Typ-Conversion" dazu...
Letztere ist Teufelszeug. Option Strict tut not.
Wir reden hier ständig von Generalisierung. Warum siehst
du, Michael, die Wiederverwendbarkeit *nur*
Anwendungsübergreifend, ja, geradezu weltumspannend?
Weil ich im dritten Semester im dritten Kellergeschoß
des Instituts für theoretische Physik, Haus 3 schwören
mußte, mich mit keiner Formel zu bescheiden, die weniger
als alles erklärt. Ich mußte diesen Schwur in dreifacher
Ausfertigung mit je drei Kreuzen meines Blutes
unterzeichnen. ;-)
... Ich teile deinen Standpunkt, dass Klassen
generalisiert sein sollten, aber ich sehe diese
Generalisierung in unterschiedlich weitgestecktem
Kontext.
Wenn die Zugriffsklasse mehr oder weniger leer ist, weil
sie nur eine generische Produktivklasse umhüllt, kann man
darüber nachdenken (s. u., ich lasse mich über diesen Aspekt
bei Prozeduren näher aus).
Da ich mit Entität("Kunde").Eigenschaft("Vorname") keinerlei
Problem habe, wäre mir das Schreiben solcher Wrapper aber
zu viel unnötige Arbeit.
Zumal ich ein Verfechter (und noch eine Grundsatzdiskussion
;-) ) von exzessiven Variablengebrauch bin:
Dim Kunde As Entity
Set Kunde = New Entity
Kunde.Source = "tblKunde"
Kunde.Id = Me.Controls("idKd").Value
etc.
Um sprechende Namen im Code zu haben, muß der Name der
Klasse nicht selbst sprechend sein, es genügt, die benutzte
Variable so zu nennen.
(Der Ehrlichkeit halber sei gestanden, daß sprechende Namen
für mich meist t, z, i, n lauten ;-) )
Post by Michael Zimmermann<Gottfried, der über die Stränge schlug...>
Auch das hätte nicht sein müssen.
Grober Klotz, grober Keil ist bekannt?
Entschuldigung siehe oben! Hoffentlich ist das für dich
OK, ...
Ja, klar.
... den beleidigen wollte ich dich natürlich nicht.
Ich hatte mich schon gewundert.
Durch deine deutliche Ablehnung des OOP-Zugangs ...
Wie kommst Du denn nur darauf? Ich krittele natürlich
ständig daran herum. Durch Meckerei werden Schwächen
aufgezeigt, deren Beseitigung oder Vermeidung dann zur
Verbesserung des Konzepts beiträgt.
Ich meckere nur über Dinge, mit denen ich mich beschäftige
und die mich interessieren. Sonst bräuchte ich zum einen
nicht zu meckern und wüßte zum anderen ja auch gar nicht,
worüber.
Vorbehaltlose Begeisterung ist immer auch Stillstand. Wenn
etwas konstruktiv war, war's eine Kritik.
... und Aussagen wie "Klassenprogrammierung <ist> recht
robust und nicht sonderlich schwierig" ...
Eine Wasser-Klasse siedet genauso bei 100° wie eine
Wasser-Function.
Sei doch froh, wenn das jemand so deutlich sagt. Ich habe
in Kursen immer wieder festgestellt, daß Teilnehmer den
Umgang mit Klassen gar nicht erst lernen wollten, weil das
ja soo schwer ist und es beim anstehenden Problem ja auch
ohne geht.
Wenn einer, weil man ihm diesen unsinnigen Respekt genommen
hat, erstmal eine Sammlung von verwandten Subs und Functions
in eine Klasse packt, ist das zwar nicht der Schatz der
Zwerge, aber ein problemloser und nicht sonderlich
schwieriger erster Schritt. Und: Es ist eine Klasse.
Bald schon kommt er auf die Idee, die Sub SetValue und
die Function GetValue als /eine/ Property Value anzusehen,
weil er die strukturale Gleichheit von Property Let mit
einer Sub und Property Get mit einer Function erkennt.
Irgendwann geht ihm dann auf, wie praktisch es ist, im
Initialize- und Terminate-Ereignis automatisch Code
ausführen zu können.
Irgendwann drängt es ich auf, Klassen als Datentyp von
Eigenschaften zu verwenden und Objekthierarchien zu
bauen, nachdem er das Mysterium von _NewEnum entschleiert
hat, Ereignisse zu nutzen, nachzulesen, was Kapselung
bedeutet und warum sie wichtig ist, sich über Polymorphismus
Gedanken zu machen und über die fehlende Vererbung zu
jammern.
Warum willst Du es denn einem Novizen verleiden, sich
überhaupt mit dem Thema zu befassen, indem Du das Pferd
von hinten aufzäumst? Soll man zum Einstieg wirklich sagen,
daß er die Finger von Klassen lassen soll, solange er sich
nicht mit Weak Referencies befaßt hat, obwohl sein aktuelles
Problem (und seine nächsten zwanzig Probleme) vielleicht gar
keine reziproken Objektbezüge braucht?
Wie bringst Du Deinen Erstklässlern das Lesen bei? Mit Hegel
und Arno Schmidt?
... habe ich den Schluss gezogen, dass
du dich damit nicht soviel beschäftigt hast.
Da ich einer Deiner "Lehrer" war, der, der Dir damals
beigebracht hat, wie man in VBA mittels Notepad, der
besten IDE aller Zeiten, die Automatische Enumeration und
die Prozedurattribute festlegt ("Auflistungsklasse und
VBA", weißt Du noch?), nahm ich an, Du wüßtest, daß ich
mich damit beschäftigt habe. Vor diesem Hintergrund
hatte ich es einfach als plumpe Anmache aufgefaßt.
Hatte mich etwas erstaunt, weil es nicht zu Dir paßt,
aber wenn's da steht...
<Michael>
Post by Michael ZimmermannWenn Du ein ganz spezielles Problem zu lösen hast, laß
es bleiben.
Stelle erst alle benötigten Formeln zusammen, ermittle
dann mit Größenvariablen die gesuchte Zielgröße und
setze erst /ganz am Schluß/ die aufgabenspezifischen
Zahlen (Daten) Deiner Ausgangsfragestellung in diese
allgemeine Lösung ein.
Schreibe dieselbe in Deine Formelsammlung und habe bei
weiteren gleichartigen Problemen keine unnötige Arbeit
mehr, weil Du einfach nur die geänderten Parameter
einsetzen mußt.
Jeder Lösungsweg, der frühzeitig auf spezifische Werte
zugreift und nicht sicherstellt, daß er für möglichst
viele Fälle allgemein anwendbar ist, ist
unwissenschaftlich. Die Lösung soll so allgemein wie
möglich sein, damit sie auf möglichst viele Fälle
anwendbar ist.
<Michael an anderer Stelle>
Post by Michael ZimmermannMeine Meinung zu Assistenten und Code-Generatoren
müßtest Du aber kennen. Das ist nichts, womit man mich
irgendwohin locken kann.
Für mich ist aber gerade so ein Generator etwas wie eine
"MetaFormel", den er schafft es aus einer allgemeinen
DB-Struktur eine spezielle Lösung zu erzeugen.
Wundert es Dich, wenn ich Dir sage, daß ich die Schrulle
habe, Rechenergebnisse von Taschenrechnern im Kopf
nachzurechnen, weil ich den Dingern nicht traue?
Per Code erzeugter Code ... schauder.
Ich schaffe einmal mit viel Aufwand eine generalisierte
Lösung, die ich dann in meine "Generatorsammlung"
eintrage um dann bei "weiteren gleichartigen Problemen
keine unnötige Arbeit mehr zu haben, weil ich nur die
geänderten Parameter einsetzen muss"
Wenn Du damit automatisch auf eine geänderte DB-Struktur
reagierst, gibt das zwar keinen Freispruch, aber immerhin
mildernde Umstände. ;-) Ich bevorzuge dennoch die klassische
Klassen- oder Funktionsbibliothek.
Außerdem schreibst du oben "möglichst viele Fälle"...
Genau so meine ich auch die Generalisierung in
unterschiedlich weit gestecktem Kontext.
Schon okay, aber wenn Du bis in die spezifische Datenebene
hineingehst, ist das keine Generalisierung mehr.
Post by Michael ZimmermannBezogen auf die Ausgangsfrage: Muß es denn generisch
sein? Ja, und nicht nur die Klassen, sondern jedwedes
problemorientierte Verhalten.
...
Wie gesagt: Wenn die Generalisierung ausreicht, dass ich
innerhalb einer komplexen Anwendung wiederkehrende
Probleme besser, sauberer und schneller lösen kann (ja
sogar besser, schneller und sauberer als mit Funktionen a
la "HoleWert()"!), dann mache ich das eben so.
"Ich mache das eben so" <> "Man sollte das so machen"
Ich komme Dir an dieser Stelle so weit entgegen, daß ich
solche Spezialisierungen zu Abkürzungszwecken für akzeptabel
halte, wenn sie keine eigene Intelligenz enthalten, sondern
auschließlich der Kapselung des Aufrufs der generischen
Prozedur/Klasse dienen.
Das Grundproblem hatten wir schon zu Anfang genannt, und
Du hast es dort auch solches eingesehen:
Sobald Funktionalitäten mehrfach vorliegen (Klassen, die
die Tabellenstruktur nachmodellieren, etwas aufwendigere
"Hole"-funktionen), müssen Code-Änderungen an vielen Stellen
womöglich von verschiedenen Personen vorgenommen werden.
Dieser Vorgang ist immer ein Fehlerrisiko (und unnötige
Arbeit).
Nochmal ein Beispiel zu Hole: Der hochspezialisierte
Funktionsstapel enthält in jeder der vielen Prozeduren
einen Sortieralgorithmus. Dieser soll irgendwann auf
einen effizienteren Algorithmus umgestellt werden.
Stellt sich bei vielen Prozeduren/Klassen die Frage: Ist
die Aktualisierung auch bei keinem der in etliche Dlls
verteilten Vorkommen vergessen worden?
Post by Michael ZimmermannDu hast mich inzwischen davon überzeugt, Paul, daß
fehlende Klassengeneralisierung keine Frage des
Gefallens oder Nichtgefallens, sondern tatsächlich
eine objektive Fehlentwicklung ist.
Du hast dich noch nicht dazu geäußert, wie du über die
.NET-Welt denkst.
Finster. Ich sehe wenige Verbesserungen, denen eine Legion
von Unnützem entgegensteht.
Dort ist ja alles Objekt.
Nein, zum Glück nicht. Das ist als Lippenbekenntnis
herbeigequält. Ein echtes Objekt ist immer explizit im
Code vom Programmierer aus der entsprechenden Klasse
zu instanzieren.
Daß Du in .net einen String benutzen kannst, ohne daß Du
vorher explizit einen Konstruktor aufgerufen haben mußt
bzw. ein Mutterobjekt brauchst, wovon Du den String als
Eigenschaft ableitest, oder daß Du die Zuweisung t = "Hallo"
machen kannst, ohne eine Property anzugeben, die diese
Zuweisung aufnehmen soll, sind klare Indizien, daß es kein
echtes Objekt ist.
Sag jetzt nichts von Default-Properties. Das ist beim
String die schreibgeschützte Chars()-Eigenschaft.
"Hallo" ist auch kein "literales Objekt", daß man das als
Objektzuweisung auffassen könnte, denn "Hallo".Length
z. B. ist ein Fehler.
Wie kommt also das "Hallo" in das String-Objekt? Vielleicht
wird es ja heimlich ganz unobjektig als Byte-Vektor an eine
Speicheradresse geschrieben wie bei einem /Werte/typ?
Es heißt dann ja etwas tricky "nativer Typ", die Bezeichnung
"primitives Objekt" habe ich dafür auch schon gelesen; eine
freundliche Umschreibung für "kein Objekt".
Daß es auch in der Objektorientierung irgendwann einen
Abschluß geben muß, der kein Objekt ist, erscheint mir
evident: Irgendwo muß der regressus infinitum, der entsteht,
wenn Prädikate selbst wieder Objekte sind, ja ein Ende
finden, weil man bei Prädikaten erster Stufe, die selbst
nicht mehr Objekt sein können, angelangt ist.
Wenn Du das ganz ernst nimmst, sieht das so aus:
(Angenommen,die String-Klasse hätte eine Value-Eigenschaft,
die selbst ein Objekt der Klasse String ergibt)
Console.WriteLine(t.Value.Value.Value.Value...)
Was tun? Default? Gib's nur einmal, wehe, wenn so ein
Dilemma zweifach auftaucht. Außerdem: Prinzipienreiterische
Objektfanatiker benutzen keine Defaults.
Wenn die Blätter (Endglieder in Hierarchien) in den
Objekteigenschaften primitive Datentypen sind, also keine
Objekte mehr, dann ist an dieser Stelle sofort Schluß:
Console.WriteLine(t.Value)
Verstehe das jetzt nicht wieder als Objektverteufelung. Ich
mein's nur gut. In einer guten objektorientierten Sprache
soll es auch Nicht-Objekt-Datentypen und Prozeduren geben.
Ich meine, mit .net hat man aus Marketinggründen das Kind
mit dem Bad ausgeschüttet. Ich kenne nur wenige, die voller
Begeisterung umgehend ihr VB.Classic dafür weggeschmissen
hätten. Die meisten sind skeptisch und quälen sich damit,
weil man ja irgendwie am Ball bleiben muß.
Eine konsequente Weiterentwicklung des klassischen VB
mit Verstärkung der Objektfähigkeiten unter Beibehaltung
der prozeduralen Möglichkeiten wäre die bessere Wahl
gewesen. Revolutionäre Änderungen tun nie gut. Bei jeder
Revolution gibt es einen Haufen Leichen, und die Revoluzzer
machen nach wenigen Jahren genau das gleiche, was sie den
Reaktionären vorgeworfen haben.
Der Inbegriff der objektorintieten Sprachen C++ kommt seit
Urzeiten mit seinem prozeduralen Kern C problemlos klar.
Und der DataSet-Generator und neuerdings die Templates
sind schon großartige Werkzeuge. Alles eine
Fehlentwicklung?
Ich halte das DataSet-Prinzip und die dahinterstehende
Idee des Datenbank-Handlings in der Tat für eine einzige
Katastrophe. Nein, /nicht/, weil es Objekte sind. ;-)
Das gesamte DataSet-Umfeld entspricht weder in seiner
Struktur noch in seiner Begrifflichkeit der mathematischen
Theorie der Tupelmengen.
Und es entspricht auch nicht der Anwendungsarchitektur, die
mir - natürlich dann nicht mit Jet - vorschwebt: Ein
allmächtiger Server, der sämtliche dummen Clients ständig
unter Kontrolle hat. Ich will keine unverbundene
RAM-Datenbank.
Die Objekthierarchie ist schwammig. Ich erwarte saubere
Strukturen, wie z. B. in Excel
set a = New Application
Set b = a.Workbooks(i) oder a.Workbooks.Add
set s = b.WorkSheets(i) oder s.Worksheets.Add
set r = s.Range("A1")
v = r.Value
Es gibt kein New Value, kein New Range etc.:
Erst Anwendung, dann Workbook usw. Es gibt zu dieser
Abfolge keine Syntax-Varanten, sondern genau einen
vorgeschriebenen Weg: Klares Konzept.
Es gibt nur einen Schönheitsfehler, daß man auch ein
Workbook erzeugen kann, und die Anwendung sich davon
ableitet. Das ist häßlich, aber auch die einzige Macke.
Bei .net, speziell ADO.net ist es oft wie auch schon
bei ADO:
Es gibt keine klare Hierarchie, sondern ein klebriges
Spinnennetz: Man kann bei allen möglichen Objekten
einsteigen und andere davon ableiten. Daß dieselbe
Funktionalität auf etliche, deutlich unterschiedliche
Weisen erreicht werden kann, ist für die Entwicklung
ein Übel. Jeder muß jede Syntax-Variante kennen, weil
er sonst den Code anderer nicht versteht. Zumindest
gibt es einen unnötigen Zeitaufwand beim Einarbeiten
bzw. Lernen, der vermieden würde, wenn jeder genau gleich
programmieren müßte, weil es einfach nicht anders geht.
Nochmal: Es geht nicht um Klassenverteufelung, es geht um
das rechte Maß. Klassen sind ebensosehr in der modernen
Softare-Entwicklung unverzichtbar, wie sie andererseits
keine alleinige Heilslehre sind. (Letztere Auffassung
unterstelle ich Dir, Gottfried, im Stillen immer ein
bißchen.)
Jesus hat schon vor ca. 2000 Jahren prophetisch gesagt:
Die Klassen sind um des Programmierers willen da, und nicht
der Programmierer um der Klassen willen.
Gruß aus Mainz
Michael