AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

verschachtelte function?

Ein Thema von alienous · begonnen am 21. Aug 2006 · letzter Beitrag vom 22. Aug 2006
Antwort Antwort
Seite 3 von 3     123   
Benutzerbild von negaH
negaH

Registriert seit: 25. Jun 2003
Ort: Thüringen
2.950 Beiträge
 
#21

Re: verschachtelte function?

  Alt 21. Aug 2006, 21:55
Zitat:
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.
Siehst du und da meine ich arbeitest du ineffizient.

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:
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;
Das ist das was du propagierst

Delphi-Quellcode:
  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;
1.) man sieht wohl den Unterschied in der Lesbarkeit
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
  Mit Zitat antworten Zitat
alienous

Registriert seit: 27. Jan 2006
94 Beiträge
 
#22

Re: verschachtelte function?

  Alt 22. Aug 2006, 00:02
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!
  Mit Zitat antworten Zitat
Der_Unwissende

Registriert seit: 13. Dez 2003
Ort: Berlin
1.756 Beiträge
 
#23

Re: verschachtelte function?

  Alt 22. Aug 2006, 10:21
Zitat von alienous:
alles klar, habs verstanden! vielen dank.
wieder etwas gelernt!
Das ist gut (wirklich!)

Zitat von negaH:
Zitat:
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.
Siehst du und da meine ich arbeitest du ineffizient.
Interessante Meinung

Zitat von negaH:
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.
Was genau möchtest du mir denn hier unterstellen?! Mir wäre nicht klar, dass man alle Details einer Implementierung im Kopf finden könnte (oder alle Programme bestehen nur aus einem Kopf). Dass Delphi seine Variablen/Methoden immer schon vor ihrer Implementierung bekannt macht ist keineswegs ein Feature das ich beführworte. Finde das andere Sprachen, wie Java, die Dinge erst einführen wenn sie wirklich verwendet werden sehr viel besser.
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 von negaH:
Was ist den das Gegenteil der Funktionen, und eben nested Funktionen ? Spaghetti-code !
Von welchen Funktionen redest du denn bitte? Erstmal ist Spaghetti-Code auch innerhalb von Funktionen ohne weiteres Möglich und auch in einer nested Function kann ich sicherlich welchen unterbringen. Das hat doch nichts mit Alternativen zu tun. Ich (und kein anderer hier) habe doch nie behauptet, dass man keine Funktionen verwenden soll. Bleib doch einfach erstmal bei dem was hier gesagt wurde!
Es geht um so genannte nested Functions! Und wo ist jetzt der gut leserliche Vorteil zwischen :

Delphi-Quellcode:
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;
und dem was ich wirklich propagiere!

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 von negaH:
Zitat von negaH:
1.) man sieht wohl den Unterschied in der Lesbarkeit
Klar, finde die Klasse ist sehr leicht lesbar. Ich sehe dass es sich hier um zwei Methoden handelt und kann die sehr leicht getrennt voneinander betrachten.
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 von negaH:
2.) Convert() als Funktion wird ausschließlich nur in dieser Funktion benötigt und um Namens Kollisionen zu vermeiden machen wird sie nested
Was natürlich ein weiterer Nachteil ist. Was ist denn wenn ich eine äussere Funktion habe, die auch convert heißt? Jetzt merke ich mir nicht alle nested Functions und komme schnell zu dem Punkt, an dem ich zwei Funktionen verwechsel (und mir Ergebnisse nicht erklären kann).
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 von negaH:
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
Ok, darüber habe ich mir keine Gedanken gemacht, aber wieviel bringt das ganze? Ich meine klar die Relationen sind hier schon klar, doch der erste Cache-Miss könnte die Vorteile hier schon deutlich dominieren (was so pauschal auch falsch ist, aber egal).

Zitat von negaH:
Gibt es eine procedurale Modularisierung in einer Programmiersprache so gibt es dort auch konsequenter Weise die nested Funktionen als stärkste Abstraktionsebene.
Dazu kann ich nur nochmal sagen, dass es nie darum ging. Alles was ich sagte ist, dass es andere Mittel gibt (da stimmen wir ja völlig überein) um Abstraktion zu erreichen. Ich finde einfach, dass die Lesbarkeit vom Code durch nested-Functions eingeschränkt wird. Der Vorteil (den ich nicht kannte und jetzt dazu gelernt habe) liegt in dem Perfomanteren übergeben von Parametern an die nested Function.

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:
procedure doA;
  var x : Integer;
  
  procedure doB;
  var y : Integer;
     
     procedure doC;
     var z : Integer;
     begin
       //....
     end;

   begin
     // ....
   end;

begin
  // ...
end;
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.
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
  Mit Zitat antworten Zitat
xaromz

Registriert seit: 18. Mär 2005
1.682 Beiträge
 
Delphi 2006 Enterprise
 
#24

Re: verschachtelte function?

  Alt 22. Aug 2006, 11:19
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 von Der_Unwissende:
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!)).
In meinem konkreten Beispiel ist es nicht möglich, einzelne Funktionen auszulagern. Wenn die ginge, dann hätte ich es auch gemacht. Ich muss sagen, Vorschläge zu machen, ohne das Problem zu kennen, finde ich etwas komisch.
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 .

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:
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;
Das sieht übersichtlich aus und benötigt sicher keine Klasse.

Gruß
xaromz
Gruß
xaromz
I am a leaf on the wind - watch how I soar
  Mit Zitat antworten Zitat
Der_Unwissende

Registriert seit: 13. Dez 2003
Ort: Berlin
1.756 Beiträge
 
#25

Re: verschachtelte function?

  Alt 22. Aug 2006, 12:47
Zitat von xaromz:
Delphi-Quellcode:
type
  TItem = class(TList);

procedure GoThroughTrees(Trees: TList);
Das sieht übersichtlich aus und benötigt sicher keine Klasse.
Ausser TItem und TList
  Mit Zitat antworten Zitat
xaromz

Registriert seit: 18. Mär 2005
1.682 Beiträge
 
Delphi 2006 Enterprise
 
#26

Re: verschachtelte function?

  Alt 22. Aug 2006, 12:53
Zitat von Der_Unwissende:
Ausser TItem und TList
I am a leaf on the wind - watch how I soar
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 3 von 3     123   


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 19:09 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