Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi uses im interface und implementation-Teil (https://www.delphipraxis.net/127553-uses-im-interface-und-implementation-teil.html)

mashutu 15. Jan 2009 11:29


uses im interface und implementation-Teil
 
Hi,

ich hatte gerade Streit mit einem Kollegen, der der Meinung ist man sollte unbedingt alle uses-Anweisungen, die nicht im Interface-Teil zwingend benoetigt werden, in den Implementation-Teil verschieben.

Ich persoenlich vermeide das vollstaendig und bislang kannte ich eigentlich auch nur Leute, die das ebenfalls gemieden haben wie der Teufel das Weihwasser.

Meine (zugegeben sehr wenigen) Argumente konnten ihn nicht ueberzeugen:

+ man baut (evtl. unbeabsichtigt) zirkulaere Bezuege auf
+ ist die Uses-Klausel nur an einer Stelle definiert sehe ich viel schneller und leichter, was da schon drin ist, als wenn ich an zwei Stellen suchen muss
+ durch zirkulaere Bezuege werden Unit-Tests schwerer zu handlen

Da gibt es doch aber noch mehr Argumente, warum man das nicht machen soll. Hat jemand Links oder Argumente?

Ich nehme auch Argumente an, die DAFUER sprechen, moeglichst viel im uses-Teil der Implementation unterzubringen (der Kollege behauptet es kompiliert dann schneller).

Danke im Voraus

mkinzler 15. Jan 2009 11:35

Re: uses im interface und implementation-Teil
 
Zitat:

+ man baut (evtl. unbeabsichtigt) zirkulaere Bezuege auf
Gerade andersrum, wenn du alles immer im Implementierungsteil einbindest verhinderst du das

QuickAndDirty 15. Jan 2009 11:42

Re: uses im interface und implementation-Teil
 
Du solltest nach Möglichkeit nur Units im Interface uses angeben die du da angeben musst.
Alles andere gehört in das uses des Implementationteil um zirkuläre Verknüpfungen zu vermeiden.

Tut mir leid dir das zu sagen aber der Kollege hat sowas von Recht. Ich würde mir einfach überlegen
wie du ihm deine Einsicht mitteilst und den Streit als Freunde beilegst.

Ansonsten es gibt Argumente dafür, Denkfaulheit zum Beispiel.

mashutu 15. Jan 2009 11:48

Re: uses im interface und implementation-Teil
 
Zitat:

Zitat von mkinzler
Zitat:

+ man baut (evtl. unbeabsichtigt) zirkulaere Bezuege auf
Gerade andersrum, wenn du alles immer im Implementierungsteil einbindest verhinderst du das

Das meine ich ja, wenn man immer alles im Interfaceteil einbindet, macht dich der Compiler schon auf den zirkulaeren Bezug aufmerksam.
Wenn man aber generell alles in den Implementation-Teil schiebt, dann bekommt man das u.U. gar nicht mit.

QuickAndDirty 15. Jan 2009 11:52

Re: uses im interface und implementation-Teil
 
Zitat:

Zitat von mashutu
Zitat:

Zitat von mkinzler
Zitat:

+ man baut (evtl. unbeabsichtigt) zirkulaere Bezuege auf
Gerade andersrum, wenn du alles immer im Implementierungsteil einbindest verhinderst du das

Das meine ich ja, wenn man immer alles im Interfaceteil einbindet, macht dich der Compiler schon auf den zirkulaeren Bezug aufmerksam.
Wenn man aber generell alles in den Implementation-Teil schiebt, dann bekommt man das u.U. gar nicht mit.

Hääää, die Typen sind doch dann bereits bekannt...also vollkommen unproblematisch... weist du eigentlich
was du da schreibst?

mkinzler 15. Jan 2009 11:53

Re: uses im interface und implementation-Teil
 
Der Fehler tritt nur auf wenn du die Units beidseitig im Interface-Teil einindest! Deshalb verhindert das Einbinden in der Implementierung genau das.

mashutu 15. Jan 2009 11:54

Re: uses im interface und implementation-Teil
 
Zitat:

Zitat von QuickAndDirty
Du solltest nach Möglichkeit nur Units im Interface uses angeben die du da angeben musst.
Alles andere gehört in das uses des Implementationteil um zirkuläre Verknüpfungen zu vermeiden.

Nein mit uses Anweisungen im Implementation-Teil werden zirkulaere Verknuepfungen erst moeglich. Ansonsten meckert schon der Compiler.

Zitat:

Zitat von QuickAndDirty
Tut mir leid dir das zu sagen aber der Kollege hat sowas von Recht. Ich würde mir einfach überlegen
wie du ihm deine Einsicht mitteilst und den Streit als Freunde beilegst.

Ansonsten es gibt Argumente dafür, Denkfaulheit zum Beispiel.

Ok, ich habe kein Problem damit einen Irrtum/Fehler hier oder meinem Kollegen gegenueber zuzugeben, aber was ist denn (ausser dem fuer mich nicht ueberpruefbaren Geschwindigkeitsvorteil) sonst noch ein Grund fuer deine Argumentation. Denkfaulheit ist wohl ein ebenso schwaches Argument wie mein Argument, dass ich nicht gerne an zwei Stellen im Quelltext suche.

mashutu 15. Jan 2009 11:58

Re: uses im interface und implementation-Teil
 
Zitat:

Zitat von mkinzler
Der Fehler tritt nur auf wenn du die Units beidseitig im Interface-Teil einindest! Deshalb verhindert das Einbinden in der Implementierung genau das.

Ich will zirkulaere Bezuege gaenzlich vermeiden und moechte daher, dass der Compiler den Entwickler auf diesen Misstand aufmerksam macht - das funktioniert aber nicht, wenn jeder alles in die uses-clause des Implementation-Teils schaufelt.

QuickAndDirty 15. Jan 2009 12:00

Re: uses im interface und implementation-Teil
 
Zitat:

Zitat von mashutu
Zitat:

Zitat von QuickAndDirty
Du solltest nach Möglichkeit nur Units im Interface uses angeben die du da angeben musst.
Alles andere gehört in das uses des Implementationteil um zirkuläre Verknüpfungen zu vermeiden.

Nein mit uses Anweisungen im Implementation-Teil werden zirkulaere Verknuepfungen erst moeglich. Ansonsten meckert schon der Compiler.

Ja, weil es vollkommen OK ist überkreuz oder zirkulär zu verweisen.

Es geht nur wegen des beschränkten Konzpets von Objekt-Pascal nicht im Interfaceteil.

taaktaak 15. Jan 2009 12:30

Re: uses im interface und implementation-Teil
 
Moin, Moin.

Die bisherigen Beiträge bringen mich als Laien-Programmierer doch sehr durcheinander. Die von mashutu im ersten Beitrag genannten Argumente halte ich für absolut zutreffend; sie entsprechen exakt meiner Denk- und Vorgehensweise!

Zirkuläre Bezüge können, auch wenn sie manchmal recht praktisch sind, letztendlich mehr Ärger machen als Nutzen bringen. Aufgrund eigener negativer Erfahrungen vermeide ich sie grundsätzlich. Daher kommt bei mir auch alles in den interface-Teil - weil ich, ebenso wie mashutu, ein Meckern des Compilers provozieren will. Allein dies ist für mich bereits Grund genug, genau diese Vorgehensweise zu wählen.

Die Aussage von mkinzler in Beitrag #2 - gilt sie noch? - ist doch vor dem Hintergrund des Grundgedankens "ich will, dass es knallt" nicht richtig. Nur mittels "verteilter" Angabe der uses im interface- und implementation-Abschnitt sind doch zirkuläre Bezüge möglich.

Tyrael Y. 15. Jan 2009 12:56

Re: uses im interface und implementation-Teil
 
Den letzten Beitrag von muetze nicht überlesen hier

...eine Anmerkung hab ich noch dazu

Wieso mache ich mir nicht eine Unit in der ich alle von mir benötigten Variablen global definiere? Ich passe einfach auf, dass ich JEDE Variable hier definiere und dabei alle Variablen alphabetisch anordne, so dass einen kleinen Überblick darüber habe....dann brauch ich auch nur noch an einer Stelle zu suchen....

weil?...ok mehr Speichernutzung...und sonst?....genau...ich benutze alles nur da, wo ich es auch brauche

uligerhardt 15. Jan 2009 12:59

Re: uses im interface und implementation-Teil
 
Zitat:

Zitat von mashutu
Ich will zirkulaere Bezuege gaenzlich vermeiden und moechte daher, dass der Compiler den Entwickler auf diesen Misstand aufmerksam macht.

Nur mal, um sicher zu gehen, dass ich dich recht verstehe - du möchtest so etwas
Delphi-Quellcode:
TControl = class(TComponent)
  property Parent: TWinControl read FParent write SetParent;
end;
 
TWinControl = class(TControl)
  property Controls[Index: Integer]: TControl read GetControl;
end;
vermeiden? :mrgreen:

Uli.

mashutu 15. Jan 2009 13:16

Re: uses im interface und implementation-Teil
 
Zitat:

Zitat von uligerhardt
Nur mal, um sicher zu gehen, dass ich dich recht verstehe - du möchtest so etwas
Delphi-Quellcode:
TControl = class(TComponent)
  property Parent: TWinControl read FParent write SetParent;
end;
 
TWinControl = class(TControl)
  property Controls[Index: Integer]: TControl read GetControl;
end;
vermeiden? :mrgreen:
Uli.

Nein so etwas will ich nicht vermeiden. Aber ich will vermeiden, dass Unit A unit B benutzt UND umgekehrt, weil man es sonst wesentlich schwerer hat modulare Tests zu machen. Solche Zirkelbezuege sind (IMHO) ueberfluessig und weisen auf Designfehler im Code hin, die ich rechtzeitig erkennen will.

taaktaak 15. Jan 2009 13:21

Re: uses im interface und implementation-Teil
 
Hmmm, meine Verwirrung steigt :shock:
Was haben zirkuläre Referenzen mit globalen Variablen und der Sichtbarkeit von Klassen im Sinne der hier zur Diskussion gestellten Vorgehensweise zu tun? Das einzige Gegenargument, was ich bisher nachvollziehen konnte ist das von Muetze: Verlangsamung der Compilierung bei > 2 Mio Codezeilen....

Phoenix 15. Jan 2009 13:35

Re: uses im interface und implementation-Teil
 
Zitat:

Zitat von mashutu
Nein so etwas will ich nicht vermeiden. Aber ich will vermeiden, dass Unit A unit B benutzt UND umgekehrt, weil man es sonst wesentlich schwerer hat modulare Tests zu machen. Solche Zirkelbezuege sind (IMHO) ueberfluessig und weisen auf Designfehler im Code hin, die ich rechtzeitig erkennen will.

Derartige Bezüge sind bei einem wirklich sauberen Code-Design (= 1 Klasse -> 1 Unit) sogar zum Teil absolut notwendig.

Ausserdem gibt es nur einen einzigen Grund, warum der Delphi-Compiler in diesem Moment meckert: Delphi ist ein Single-Pass Compiler und würde sonst in eine Endlosschleife rennen. Wäre es ein Multipass-Compiler, dann würde er sich gar nicht erst an der ersten Unit-Liste aufhalten, sondern gleich den Interface-Teil parsen, und erst wenn er einen unbekannten Typen entdeckt die vorher angegebenen Units danach durchsuchen.

Wenn die andere Unit hingegen im implementation-Teil steht, dann hat er bereits alle notwendigen Typen der Klassendeklaration geparst und kann gefahrlos weiterarbeiten.

Solche Referenzen sind in der sauberen, strukturierten Programmierung üblich, ein wichtiges Hilfsmittel und lassen sich auch ohne Probleme automatisiert testen.

Du würdest (bei einem sauberen Code-Design (nochmal: genau eine Klasse gehört in genau eine Unit) damit sämtliche Forward-Declarations verbieten. Andersrum: Wenn Du nach genau dieser Regel konsequent arbeiten würdest, hättest Du in Deinen Units keine Forward-Declarations mehr. Entferne mal alle und gucke, ob es sich dann noch kompilieren lässt.

Dein Kollege hat im übrigen vollkommen recht: Die Uses-Listen sollten immer optimiert sein, keine unnötigen Units enthalten und wenn eine Unit nur in der Implementierung benötigt wird, dann ist es sauber, sie auch nur dort einzubinden wo sie benötigt wird. Andernfalls könnte es nämlich insbesondere hier bei Delphi sogar passieren, dass unter Umständen eine initialization-Teil einer Unit zu früh durchlaufen wird, weil sie oben im Interface stand anstelle im Implementation. Mal von der Compilergeschwindigkeit (und insbesondere dem Speicherverbrauch beim Kompilieren und Linken) abgesehen.

Das Hilfsmittel, um die Uses-Klauseln korrekt zu sortieren und in Deinem Fall hoffentlich schnellstmöglich das unnötige Zeug raus- und das falsch Platzierte in den implementation-Teil zu verschieben heisst Icarus Uses List Analyzer, was nicht umsonst sagt, welche Uses entfernt und verschoben gehören-

taaktaak 15. Jan 2009 13:45

Re: uses im interface und implementation-Teil
 
Ich möchte mashutu nicht vorgreifen, aber:

Das im interface keine unnötigen Units aufgeführt werden, ist doch eigentlich selbstredend.

Im übrigen entnehme ich der bisherigen Diskussion, dass zirkuläre Bezüge von den Profis nicht für schlechtes Design erachtet werden und manchmal sogar notwendig sind - korrekt?

Ist es dann bereits ein unprofessioneller Denkansatz, zirkuläre Bezüge -wann immer es geht- zu vermeiden?

Tyrael Y. 15. Jan 2009 13:49

Re: uses im interface und implementation-Teil
 
Zitat:

Zitat von taaktaak
Was haben zirkuläre Referenzen mit globalen Variablen und der Sichtbarkeit von Klassen im Sinne der hier zur Diskussion gestellten Vorgehensweise zu tun?.

Laufen tut vieles, sauber ist nicht alles. ;)


Zitat:

Zitat von taaktaak
Im übrigen entnehme ich der bisherigen Diskussion, dass zirkuläre Bezüge von den Profis nicht für schlechtes Design erachtet werden und manchmal sogar notwendig sind - korrekt?

Exakt. Zirkuläre Aufrufe sind oft gewollt und völlig sauberer Code.

Phoenix 15. Jan 2009 14:01

Re: uses im interface und implementation-Teil
 
Zitat:

Zitat von taaktaak
Ist es dann bereits ein unprofessioneller Denkansatz, zirkuläre Bezüge -wann immer es geht- zu vermeiden?

Jain. "Wann immer es geht" ist zu hart. Dieser Ansatz dazu führen, dass man sich beim Designen einen abbricht und einen Workaround einbaut, um eine Rückreferenz zu vermeiden. Nur führt dieser Workaround dann in aller Regel zu (viel) mehr Code, als eigentlich notwendig ist. Mehr Code = mehr Stellen, wo Fehler sein können. Mehr Code = mehr zu warten. Mehr Code = mehr zu testen. Und das liesse sich durch eine einfache Rückreferenz vermeiden.

Das ganze lässt sich im übrigen aber tatsächlich in 90% aller Fälle relativ einfach vermeiden: Man definiert ein Interface, und inkludiert dieses Interface in alle beteiligten Units. Interfaces sind nicht das Allheilmitteln, aber an der Stelle in den allermeisten Fällen das korrektere Hilfsmittel als überkreuzende Bezüge. Aber es gibt eben stellen, da macht auch ein Interface weniger Sinn als ein Rückbezug (insbesondere, wenn es um einen Typen geht, der nur einmal benutzt wird).

taaktaak 15. Jan 2009 14:09

Re: uses im interface und implementation-Teil
 
Ok, dieser Argumentation kann ich (zustimmend) folgen - Danke!

PS: Interfaces sind für mich derzeit (noch) ein völlig unbekanntes Terrain. Habe daher bisher im Bedarfsfall mit Botschaften gearbeitet um zirkuäre Bezüge zu vermeiden - und dies in den konkreten Anwendungsfällen auch als übersichtlich und wartungsfreundlich angesehen.

mjustin 15. Jan 2009 14:25

Re: uses im interface und implementation-Teil
 
Zitat:

Zitat von mashutu
Aber ich will vermeiden, dass Unit A unit B benutzt UND umgekehrt, weil man es sonst wesentlich schwerer hat modulare Tests zu machen. Solche Zirkelbezuege sind (IMHO) ueberfluessig und weisen auf Designfehler im Code hin, die ich rechtzeitig erkennen will.

Ich denke auch, dass verborgene Kreuz- und Querbezüge zu schlechter Software führen.

Aber nehmen wir mal M:N Beziehungen - was spricht dagegen, die beteiligten Klassen in je eine Unit zu packen? Delphi ermöglicht es, mit dem Umweg über implementation und unschöne (aber unvermeidbare) Typecasts.

Selbst in der Praxis gängige Entwurfsmuster (wie z.B. "Besucher") sind ohne zirkuläre Bezüge in Delphi nicht darstellbar, wenn man je Klasse eine Unit hat. Nachträglich alle Units wieder zu einer 'Monster'-Unit zusammenzufassen, nur um diese Bezüge zu vermeiden, fiele für mich auch nicht gerade in die Kategorie 'Modernes Design'. Es sind zwei Seiten einer Medaille - Lösungen, die funktionieren, sind nicht immer zugleich auch 'schön'.

Schade, aber es gibt m.W. keine Werkzeuge für Delphi, die Unitabhängigkeiten analysieren und gegen selbst definierte Kriterien prüfen können - z.B. um festzulegen, dass die 'Schichten' der Software nur darunterliegende 'Schichten' aufrufen dürfen. Das wäre bei großen Projekten ein enorm zeitsparendes Werkzeug.

Phoenix 15. Jan 2009 14:32

Re: uses im interface und implementation-Teil
 
Irgendwer hier in der DP (MaBuSe?) hat mal ein Tool zur Verfügung gestellt, mit der man Unit-Bezüge grafisch darstellen konnte, um die Komplexität einer Anwendung zu visualisieren. Das würde bei einer solchen grafischen Darstellung schon auffallen, wenn sich die Graphen nicht an einer Schicht 'aufhängen' lassen und dann nur runterbaumeln.

taaktaak 15. Jan 2009 14:35

Re: uses im interface und implementation-Teil
 
Zitat:

in der Praxis gängige Entwurfsmuster (wie z.B. "Besucher")
Auch wenn es hart an der Grenze zum OT ist:

Einem Laien fehlen hier vermutlich in den meisten Fällen die absoluten Basics; gibt es vielleicht eine Literaturempfehlung zum Thema "Entwurfsmuster"?

QuickAndDirty 15. Jan 2009 14:40

Re: uses im interface und implementation-Teil
 
Suche unter Pattern und Antipattern.

mjustin 15. Jan 2009 15:22

Re: uses im interface und implementation-Teil
 
Zitat:

Zitat von taaktaak
Zitat:

in der Praxis gängige Entwurfsmuster (wie z.B. "Besucher")
Auch wenn es hart an der Grenze zum OT ist:

Einem Laien fehlen hier vermutlich in den meisten Fällen die absoluten Basics; gibt es vielleicht eine Literaturempfehlung zum Thema "Entwurfsmuster"?

"Entwurfsmuster von Kopf bis Fuß" von von Eric Freeman (Autor), Elisabeth Freeman (Autor), Kathy Sierra (Autor), Bert Bates (Autor)

Es ist angenehmer zu lesen als das Originalwerk der GoF (Gang of Four) ("Design Patterns") - auch die Java Codebeispiele sollten nicht davon abhalten, es sich mal näher anzuschauen.

himitsu 15. Jan 2009 15:30

Re: uses im interface und implementation-Teil
 
Ich hab alles im Interface, außer wenn ich absichtlich Kreuzbezüge erstellen will/muß.

Hat zumindestens den Vorteil, daß ich "alle" eingebundenen Units auf einen Blick hab.

aber wie heißt es so schön: alles was geht ist erlaubt
du bist der Programmierer, als entscheidest du, wie es gemacht wird (es sei den es gibt Vorlagen vom Chef/der Firma)

taaktaak 15. Jan 2009 16:59

Re: uses im interface und implementation-Teil
 
Zitat:

"Entwurfsmuster von Kopf bis Fuß"
Prima!
Vielen Dank!

Das schaut ja ganz unkonventionell aus,
werd' ich mir mal besorgen!

Cyf 15. Jan 2009 20:20

Re: uses im interface und implementation-Teil
 
Ok, jetzt bin ich vollkommen verwirrt, ob

a) Zirkuläre Bezüge nun gut oder schlecht sind
b) In welchen Abschnitt die uses gehören
c) Man nicht (wie in Java üblich) doch alle Klassen in einzelne Units packen sollte, aber bei "Unit" hab ich mir in Delphi ein zussammenhängendes Themengebiet vorgestellt. Selbst die RTL/VCL sind ja nicht so aufgetrennt...

:gruebel:

jfheins 15. Jan 2009 21:01

Re: uses im interface und implementation-Teil
 
[OT]
Nimm C# da stellt sich diese Frage nicht :mrgreen:
[/OT]

a) Lassen sich manchmal nicht vermeiden. Aber man muss sie auch nicht aus Spaß reintun, weil man gerade lustig ist ;)

b) Ich tu sie immer ins interface

c) In Delphi kannst du sogar auf private-Felder zugreifen wenn du in der gleichen Unit bist. Da das manche VCL-Kompos machen kann man die nicht trennen ;)

mkinzler 15. Jan 2009 21:07

Re: uses im interface und implementation-Teil
 
Zitat:

c) In Delphi kannst du sogar auf private-Felder zugreifen wenn du in der gleichen Unit bist. Da das manche VCL-Kompos machen kann man die nicht trennen Wink
Deshalb wurde auch strict private eingeführt

Zu b)Kommt darauf an. Sind in ihenen etwas deklariert, was du im Interface benötigst ( Typen für Parameter, komponenten bei Formunit, ...) dann im Interface, sonst im Implementationsteil

mashutu 16. Jan 2009 07:53

Re: uses im interface und implementation-Teil
 
Danke Euch allen fuer die vielen Antworten.
Vielleicht sollte ich kuenftig manche Sachen nicht so verbissen sehen (-:

Mit dem Kollegen (siehe erstes Posting) habe ich mich konstruktiv ausgesprochen.


Alle Zeitangaben in WEZ +1. Es ist jetzt 20:30 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz