![]() |
verschachtelte function?
hi, beim durchforsten der DP is mir mal aufgefallen, das eine function in einer procedure gab, so in der art:
Delphi-Quellcode:
kann mir jemand erklären wieso die function nich einfach über der procedure steht? wo liegt denn da der vorteil und was für unterschiede gibt es da? wollte mich selbst informieren, aber ich weiss nich wie dieses verfahren heisst! auf die schnelle viel mir nur "verschachtelte function ein :D
procedure haupt;
function verschachteln(...):String; var ... begin //inhalt der function end; var ... begin //inhalt der procedure (zb aufruf der function) end; wenn ihr mir sagt wie das verfahren nun heisst, dann editier ich das topic versprochen! danke |
Re: verschachtelte function?
Die Funktion verschachteln(...):String; ist in diesen Fall eine lokale Funktion und nur in der Prozedur haupt; sichtbar. Du kannst so in vielen Methoden eine Methode mit gleichen Namen aufrufen, ohne sie überladen zu müssen. Ob es Resourcenschonender ist kann ich jetzt nicht mit SIcherheit sagen, aber ich glaube schon. ;)
MfG freak |
Re: verschachtelte function?
Zitat:
Delphi-Quellcode:
Das hat folgenden Sinn: Die Prozedur Bla ist nur innerhalb der Prozedur Blubb aufrufbar. Zudem kann Bla auf die Parameter von Blubb, sowie auf die vor ihr deklarierten Variablen zugreifen.
procedure Blubb(x, y: integer);
var a, b: integer; procedure Bla(f: string); begin end; var s, t: integer; begin end; Gebraucht werden kann es bspw., wenn man laengere Methoden hat, in denen bestimmte Codestuecke oefters vorkommen. Um dann nicht eigene private-Methoden dafuer in die Klasse zu schieben, die das redundante Codestueck implementiert, kann diese "Funktionsintern" deklariert werden. Ob das allerdings zum schoenen Programmierstil gehoert, diese Entscheidung sei jedem selbst ueberlassen. greetz Mike |
Re: verschachtelte function?
Zitat:
|
Re: verschachtelte function?
Zitat:
|
Re: verschachtelte function?
Zitat:
Mit OO hat dies nix mehr zu tun, da kann ich ja grad alles in eine Main-Function reinschreiben. :kotz: Ich löse sowas immer mit einer Klassenmethode, evtl wird diese überladen oder mit Default-Parametern versehen... |
Re: verschachtelte function?
Hallo,
Zitat:
Wenn man z. B. eine lange Schleife in eine eigene Prozedur auslagert, dann bleibt die eigentliche Methode schön klein und übersichtlich und durch die logische Trennung in mehrere Unter-Prozeduren erhöht sich die Übersichtlichkeit noch. Natürlich kann man jede Unterfunktion in eine eigene Methode packen. Aber: Was ist, wenn ich 20 lokale Variablen der eigentlichen Methode in den einzelnen Prozeduren benötige? Soll ich dann den einzelnen Prozeduren jeweils 20 Variablen übergeben? Und welchen Sinn haben diese Methoden, wenn sie doch nur im Kontext der eigentlichen Methode sinnvoll sind? Das Beispiel mag konstruiert erscheinen, aber ich habe hier eine Methode mit 7(!) Unterfunktionen, dia alle ihre Berechtigung haben (die gesamte Methode incl. Unterfunktionen ist ca. 500 Zeilen lang). Gruß xaromz |
Re: verschachtelte function?
Zitat:
|
Re: verschachtelte function?
Hallo,
Zitat:
Gruß xaromz |
Re: verschachtelte function?
@xaromz: Was spricht in deinem Fall dagegen die Funktionen als eigenständige Funktionen zu Handhaben?
|
Re: verschachtelte function?
Hallo,
Zitat:
Gruß xaromz |
Re: verschachtelte function?
Zitat:
Nein, mal ganz ehrlich, wozu ist denn so etwas wie Objekt Orientierung gut? Soweit ich weiß ist das eine Möglichkeit Programme die etwas mehr als 3 Zeilen haben sinnvoll zu strukturieren. Wie gut jmd. diese gegebene Möglichkeit nutzt ist natürlich etwas anderes. Übersichtlich finde ich (ist nur eine Meinung) die lokalen Funktionen gar nicht. Zwar kann ich hier auf Variablen zugreifen, aber wenn ich eine 500 Zeilen Funktion (mit all ihren lokalen Funktionen zusammen) habe und 20 Parameter, dann frage ich mich warum das keine eigene Klasse ist. Natürlich kann man nicht pauschal sagen > 5 Zeilen = Klasse draus machen, aber eigene Problematik gelöst = Klasse draus machen schon! Deswegen sorry, muss ich RavenIV zustimmen, dass du eventuell einfach nur ungeeignet designst. Ich denke es gibt andere Sprachen, die keine Lokalen Funktionen erlauben (auch keine Makros oder ähnliches) die auch übersichtlichen Code hinbekommen (mit > 3 Zeilen). Gruß Der Unwissende [EDIT] Zitat:
Na ja, wenn du ein Problem löst (und es auch noch eine gewisse Komplexität übersteigt), dann lohnt sich auslagern immer. Du hast deine Methode und ihre Implementierung nach eigener Aussage mehrfach verändert. Das kannst du natürlich noch viel leichter mit einem Objekt machen. Du kannst hier einfach neue Klassen schaffen (mit gleicher Schnittstelle) und die beliebig austauschen und das alles als Basis für weitere Spezialisierungen verwenden. Taucht dein Problem noch einmal auf, kannst du einfach die Klasse (die hier die ausgelagerte Funktion ist) verwenden. Ich denke es wäre auch lesbarer, da sich alle Prozeduren immer auf einer Ebene befinden. Vorallem sehen Leute die nicht häufig (oder nie) mit lokalen Prozeduren arbeiten sofort wo Anfang und Ende einer Prozedur stehen. [/EDIT] |
Re: verschachtelte function?
Wenn man sich der Namensgebung ein wenig widmet, kann man das Logische auch recht gut abbilden.
Delphi-Quellcode:
Da sieht man doch auch auf einen Blick, was zusammen gehört.
function Rechnen ();
function Rechnen_BerechneWas (); function Rechnen_HoleWerte (); function Rechnen_WerteAusgeben (); usw. |
Re: verschachtelte function?
Zitat:
|
Re: verschachtelte function?
Ich finde die "Nested Functions" - so heißen die Viecher IMHO - manchmal auch praktisch. Zugegeben nicht immer. Aber in C# und C++(Hab grad n Ferienjob, bei dem ich C++Builder progge) fehlen sie mir manchmal sogar. Und zwar genau dann, wenn man Funktionen in Teilfunktionen aufteilen will, sich das Ganze aber nicht bzw. nur schwer oder nur eingeschränkt sinnvoll in eine Klasse auslagern lässt[1]. In gewissem Sinne(Information- bzw. FunctionHiding) entspricht das sogar den Prinzipien der OOP.
N Beispiel, das jeder kennt, und wo NestedFunctions IMHO sinnvoll eingesetzt werden: QuickSort... [1] zugegebn n schmaler Bereich... mfg Christian |
Re: verschachtelte function?
Zitat:
Und was spricht jetzt bitteschön dagegen diese 15 Zeilen Code in eine Lokale function auszulagern und in der Threadfunktion aufzurufen? Wie unübersichtlich! Welch schlechtes Softwaredesign! :roll: So findet man jedenfalls die eigenltiche *Funktion* des Threads wesentlich schneller... |
Re: verschachtelte function?
also mal ganz ehrlich: alienous hatte gefragt, worin die Bedeutung der Functionen/Prozeduren innerhalb anderer Funktionen/Prozeduren liegt. Das ist mit der Erklärung des Scopes beantwortet worden.
Jetzt entsteht hier wieder mal eine Debatte darüber, ob die Verwendung eines Faetures von Delphi guter oder schlechter Programmierstil ist. Muß das denn sein? Dann können wir ja auch gleich in ![]() Entschuldigt bitte, wenn das etwas säuerlich klingt, aber ich finde, das Diskussionen sachlich sein sollten. Anderen ein schlechtes Design vorzuwerfen, ohne dessen Programmierung zu kennen, ist sicherlich keine konstruktive Kritik. Ich für meinen Teil kann sagen, daß sowohl nested Functions als auch Auslagerung in entsprechende Klassen Ihre Berechtigung haben. Welches Mittel man wann wählt, ist dem Programmierer nunmal selbst überlassen. Gruß onlinekater |
Re: verschachtelte function?
Zitat:
Zitat:
verwendet. Allerdings wurde direkt vorher von einer Funktion mit 20 benötigten Parametern und 500 Zeilen (inkl. allen Unterfunktionen) gesprochen. Ich denke da ist es durchaus angebracht Kritik an der Funktion zu üben, 500 Zeilen sind doch wohl mit sehr hoher Wahrscheinlichkeit teilbar (und für mich komplett unleserlich). Natürlich verbietet einem keiner Funktionen in andere einzubetten. Natürlich ist das kein schlechter Programmierstil, aber definitiv kein OO Design. Imho wurde mehr nicht gesagt. Es verlangt keiner dass Delphi Programmierer OO arbeiten! Aber es bietet Möglichkeiten und ein Hinweis auf diese denke ich sind total ok. Ich seh ehrlich gesagt noch nicht den sachlichen Vorteil darin, dass ich eine Funktion innerhalb einer Funktion verwende. Als Nachteile sehe ich weiterhin, dass die Lesbarkeit reduziert wird. Man sieht meiner Meinung nach nicht sofort, wo was herkommt. Insbesondere das Variablen aus der umgebenden Funktion verwendet werden können senkt schon alleine die Lesbarkeit. Die dürften sich schwer qualifizieren lassen und sind weder als Parameter übergeben, noch in der Funktion lokal! Habe ich also 3 solcher Funktionen in einer Funktion kann ich erstmal suchen wo welche Funktion aufhört und von der untersten aus suchen, wo die Variablen deklariert sind. Insbesondere Anfänger haben (meiner Erfahrung nach) sehr viele Probleme mit dem lesen solcher Funktionen. Ohne Frage, man bekommt jedes Programm unleserlich, aber es gibt Dinge die etwas erleichtern oder erschweren. Ich sehe hier eine Möglichkeit die Lesbarkeit zu verringern, aber noch keinen Vorteil. Warum sollte eine private Methode eine andere private Methode nicht kennen? Da ich von Methoden spreche gehören sie zu einem Objekt, da sie privat sind, können beide nicht von aussen gesehen werden. Ich habe hier also eine (imho gute) Alternative. Methoden sehen immer gleich aus und ich würde sofort sehen ob es sich um lokale Variablen oder Instanzvariablen handelt (mit Qualifizierung durch self.). |
Re: verschachtelte function?
Zitat:
Nested Functions -> verschachtelte lokale Funktionen, sind ein sehr starkes Instrument in der Programmierung um ein komplexes und nicht weiter reduzierbares Problem (reduzierbar zb. per OOP) einfacher und modularisierter umzusetzen. Defakto sind nested Functions die konsequente Umsetzung des Prinzips der Abstraktion, das zb. auch in Delphi über Program -> Units -> Interface -> Implementation -> Function -> nested Function. Ich persönlich erachte also nested Functionen als sehr guten Stil. Das hat mehrere Gründe: 1.) abstraktion eines Problems durch Zerlegung in immer kleinere und übersichtlichere Teilprobleme 2.) besser Lesbar, da man wenn man eine Funktion als BlackBox verstanden hat, deren Implementierung quasi wieder vergessen kann, es interessiert dann nur noch der Name, In/Out Parameter dieser Funktionen 3.) da nested Funktionen nun mit sehr wenigen Sourcezeilen, Parameter und lokalen Variablen auskommen (entgegen eine rießigen komplexen single Funktion) kann der Delphi Compiler den erzeugten Code optimieren. 4.) es gibt keine andere Möglichkeit als eine nested Funktion wenn man ein Problem als Black Box so stark abstrahieren möchte das diese Details nirgends von aussen sichtbar sind. Dh. wenn man innerhalb einer Funktion einen Code mehrmals benötigt und diesen in eine Funktion auslagert, dann ist die stärkste Un-sichtbarkeits-stufe nur eine nested Funktion. Eine nicht-nested Funktion wäre also sichtbar für andere Funktionen, das ist aber unerwünscht. Mit nested Funktionen kann man also ein Problem nicht nur sauberer lösen sondern der erzeugte Maschinencode wird auf Grund der besseren optimierung durch den Compiler auch schneller sein. Dazu muß man aber auch wissen wie der Compiler überhaupt einen Code optimiert. In diesem Falle interessiert uns nur die Frage wie der Compiler mit den vorhandenen Prozessorregistern umgeht. Und da ist es so das diese Register der CPU in ihrer Anzahl begrenzt sind und der Compiler immer versucht möglichst viele lokale Variblen in Registern zu halten. Je komplexer eine Funktion ist desto mehr lokale Variablen wird sie benötigen und um so mehr steht der Optimierer unter Registerdruck, dh. er hat normalerweise nicht genügend CPU Register zur Verfügung um alle lokalen Variablen der Funktion darin zu optimieren. Mit nested Funktionen zerlegt man nun diese komplexe Funktion in so viele Teil-Funktionen (nested) das jede dieser Funktionen nun mit wesentlich weniger lokalen Variablen auskommen. Nun kann der Compiler diese Teil-Funktionen weit besser optimieren. Der Compiler betrachtet nämlich einen Code innerhalb einer Funktion immer als Optimierungs-Einheit, als Ganzes das er optimieren soll. Der Delphi Compiler kann NICHT Code über Funktionsgrenzen hinweg optimieren und um so wichtiger wird es das man die eigenen Funktionen so weit vereinfacht das er möglichst alle lokalen Variablen in Registern halten kann. Gruß Hagen |
Re: verschachtelte function?
Hallo,
Zitat:
Zitat:
Zitat:
Gruß xaromz |
Re: verschachtelte function?
Zitat:
Warum willst du ALLES im Kopf haben, jedes kleine Detail eine Implementierung, das ist utopisch. Konsequenz ist also das man im BlackBox-Prinzip denkt und auch einen Source liest. Das heist: man schaut sich einmalig zb. eine nested Funktion an und liest deren Implementirung. Wenn man das gemacht hat dann reicht als Information für die Zukunft nur noch der Name, Parameter und Aufgabe zu kennen, NICHT deren Implementierung. Was ist den das Gegenteil der Funktionen, und eben nested Funktionen ? Spaghetti-code ! Ein extremes Beispiel
Delphi-Quellcode:
Das ist das was du propagierst ;)
for I := 0 to x do
begin S := ''; K := I *2; while K > 0 do begin S := S + Char(Ord('0') + K mod 10) K := K div 10; end; Array[i] := S; S := ''; K := I *3; while K > 0 do begin S := S + Char(Ord('0') + K mod 10) K := K div 10; end; Array[i*2] := S; S := ''; K := I *12; while K > 0 do begin S := S + Char(Ord('0') + K mod 10) K := K div 10; end; Array[i*12] := S; end;
Delphi-Quellcode:
1.) man sieht wohl den Unterschied in der Lesbarkeit
function Convert(K: Integer): String;
begin Result := ''; while K <> 0 do begin Result := Result + Char(Ord('0') + K mod 10) K := K div 10; end; end; begin for I := 0 to x do begin Array[i] := Convert(I*2); Array[i*2] := Convert(I*3); Array[i*12] := Convert(I*12); end; 2.) Convert() als Funktion wird ausschließlich nur in dieser Funktion benötigt und um Namens Kollisionen zu vermeiden machen wird sie nested 3.) Convert() benötigt in EAX den Parameter K, und noch ein Register um Result aufzunehmen. Mehr benötigt man an registern auch nicht, dh. Convert() sollte durch den Compiler in einen Maschionencode umgewandelt werden der ohne STack auskommt. 4.) in der Funktion selber werden I,X und @Array benötigt, also 3 CPU Register. Also auch diese Funktion sollte durch den Compiler vollständig in Registern optimiert werden Im Gegensatz zum 1. Beispiel: - Spaghetti Code - I,K,X,@Array[],K,S müssen in Register, das reicht aber nicht es stehen zur Verfügung EAX,EDX,ECX und EDI,ESI,EBX wenn sie auf dem STack gesichert wurden. Nested Funktionen sind ein ganz normales Instrument der heutigen Programmierung. Gibt es eine procedurale Modularisierung in einer Programmiersprache so gibt es dort auch konsequenter Weise die nested Funktionen als stärkste Abstraktionsebene. Das Konzept hinter den nested Funktionen ist also das gleiche Konzept wie hinter dem BackBox Prinzip, der prozeduralen Programmirung, der hierarischen Modularisierung der Sourcen und Programme und auch der OOP (OOP ist nur eine andere Art und Weise der Abstraktion und Modularisierung, ihr Ziel ist aber gleich). Gruß Hagen |
Re: verschachtelte function?
alles klar, habs verstanden! vielen dank.
diskussionen wie diese finde ich persönlich sehr lehrreich. besonders hagens ausführungen waren sehr informationsreich! wieder etwas gelernt! :dancer: |
Re: verschachtelte function?
Zitat:
Zitat:
Zitat:
Aber zur Blackbox, da fahre ich mit einer z.B. abstrakten Klasse oder einem Interface um einiges Schwarzer. Da brauche ich dann gar kein Wissen über die Implementierung! (Stimmt wenn man noch Factory-Pattern und Dependency Injection hinzunimmt, dann kann es Klassen geben die nur die Schnittstelle kennen). Da seh ich jetzt einen sehr einfachen Weg um austauschbare Lösungen bereit zu stellen. Die habe ich durch die Mittel der OOP gegeben. Ich sehe also für Delphi Programme die OO programmiert werden keine Notwendigkeit der nested Functions. Zitat:
Es geht um so genannte nested Functions! Und wo ist jetzt der gut leserliche Vorteil zwischen :
Delphi-Quellcode:
und dem was ich wirklich propagiere!
function Convert(K: Integer): String;
begin Result := ''; while K <> 0 do begin Result := Result + Char(Ord('0') + K mod 10) K := K div 10; end; end; begin for I := 0 to x do begin Array[i] := Convert(I*2); Array[i*2] := Convert(I*3); Array[i*12] := Convert(I*12); end;
Delphi-Quellcode:
type
TConverter = class(TObject) private function Convert(K : Integer): String; public doFoo; end; .... function Convert(K: Integer): String; begin Result := ''; while K <> 0 do begin Result := Result + Char(Ord('0') + K mod 10) K := K div 10; end; end; procedure doFoo; ... for I := 0 to x do begin Array[i] := Convert(I*2); Array[i*2] := Convert(I*3); Array[i*12] := Convert(I*12); end; end; Zitat:
Zitat:
Von aussen ist es eine Black-Box, nur die Methode doFoo ist sichtbar. Ich habe alle Vorteile der OOP offen gehalten. Klar, könnte ich auch mit einer nested Function machen, würde für mich aber immer noch die Lesbarkeit senken (kommen wir noch darauf zurück). Zitat:
Jetzt frage ich mich aber, wie wahrscheinlich in einer Klasse (die man sauber designt) Namenskonflikte sind. Tragen die dann nicht zu einer für sich selbst sprechende Bennenung bei? Ich meine klar, convert konvertiert wohl etwas, keiner weiß jetzt was (und jeder muss in die Implementierung schauen), mir entgeht da der Vorteil. Zitat:
Zitat:
Aber auch ich möchte es noch mal deutlich machen, zerlegt man ein Problem nur innerhalb von einer Funktion in einzelne Teilprobleme und verwendet dazu nested Funktions, würde das in letzter Konsequenz zu Konstrukte führen wie
Delphi-Quellcode:
Wobei hier in doB redundante Teile aus doA auftauchen und in doC solche aus B, natürlich kann man hier noch beliebig weiterschachteln (wieviele Register bleiben da dann übrig?). Klar, ist jetzt auch ein konstruiertes Beispiel, aber die habe ich bisher hier gesehen.
procedure doA;
var x : Integer; procedure doB; var y : Integer; procedure doC; var z : Integer; begin //.... end; begin // .... end; begin // ... end; Auch hier möchte ich nur sagen, dass es Konsequent fortgeführtes Verwenden von nested Functions wäre. Ihr Einsatz lässt sich vermeiden und würde die Lesbarkeit solcher Beispiele mit Sicherheit erhöhen! Weder nested Functions noch OOP oder ein anderes Mittel der Strukturierung und Abstraktion ersetzen also ein sinnvolles Design und ich möchte nocheinmal sagen, 500 Zeilen mit allen nested Functions zusammen klingt nach einem Design, dass man verbessern könnte. Da von xaromz auch gesagt wurde, dass es hier Unterprozeduren gibt, würde ich sagen, dass man einen Teil von ihnen anders auslagern sollte (in eine eigene Unit, die diese Klasse von Problemen löst (auch ohne OOP!)). Gruß Der Unwissende |
Re: verschachtelte function?
Hallo,
ich muss, sagen ich lese die Argumente hier mit großem Interesse. Insbesondere Hagens Ausführungen zum Laufzeitverhalten sind sehr interessant. Dazu fällt mir ein, wenn ich jetzt eine Klasse baue, habe ich zwar auch in sich abgeschlossene Methoden, aber immer ein Argument mehr, welches ein Register belegt, und zwar Self. Zitat:
Vielleicht sollte ich mal schreiben, was mein "Monster" eigentlich macht: Es parst Textbausteine unterschiedlicher Art und richtet diese in einem Rechteck aus (mit Zeilenumbrüchen). Dabei müssen viele Faktoren bedacht werden: Zeilen- und Absatzumbrüche, Tabulatoren, Silbentrennung, Höhe des Rechtecks... Für all diese Teilbereiche (Tabulatorberechnung, Silbentrennung usw.) benutze ich Unterfunktionen, diese werden von der Hauptschleife aufgerufen, die alle Bausteine durchgeht. In den Unterfunktionen werden aber viele Variablen gebraucht, die auch in der Hauptschleife verwendet werden (z. B. das Einfügen einer neuen Zeile in die Bausteinliste bei einem Zeilenumbruch, der in einer Unterfunktion berechnet wurde). Klar kann ich sowas als Klasse schreiben (ich habe das sogar letzte Nacht testweise gemacht), aber: Ich benötige diese Funktion (die sehr lange dauern kann) teilweise mehrmals pro Sekunde, und da kommt es auf jeden Tick an. Ich will also nicht jedesmal erst eine Klasse erzeugen und dann Zeit bei Methodenaufrufen verschwenden. Effizienz ist hier wichtiger als alles andere. Wenn ich es besser als der Compiler könnte, hätte ich die Funktion auch komplett in Assembler gschrieben, dann hätte ich einige Tausend Zeilen. Ich finde außerdem, dass dieses Beispiel kein gutes ist, um das Für und Wider von Nested Procedures zu diskutieren, da es eine sehr spezielle Geschichte ist. Das dürfte auch mit Riesenabstand die größte Funktion sein, die ich je geschrieben habe, und ich möchte sowas eigentlich nicht noch mal machen müssen :zwinker: . Ich habe hier übrigens noch ein schönes Beispiel für Nested Procedures. Angenommen ich habe einen Baum mit mehreren Wurzeln (also eigentlich eher einen Wald). Jetzt möchte ich alle Elemente durchgehen. Das funktioniert am Einfachsten mit einer Rekursion in einer Nested Prodecure:
Delphi-Quellcode:
Das sieht übersichtlich aus und benötigt sicher keine Klasse.
type
TItem = class(TList); procedure GoThroughTrees(Trees: TList); procedure Walk(Item: TItem); var I: Integer; begin // Irgendetwas machen for I := 0 to Item.Count - 1 do Walk(Item[I]); end; var I: Integer; begin for I := 0 to Trees.Count - 1 do Walk(Trees[I]); end; Gruß xaromz Gruß xaromz |
Re: verschachtelte function?
Zitat:
|
Re: verschachtelte function?
Zitat:
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 15:19 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz