AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren

Prozedur-Parameter mit variantem Typ?

Ein Thema von dizzy · begonnen am 19. Mai 2004 · letzter Beitrag vom 20. Mai 2004
Antwort Antwort
Seite 1 von 3  1 23   
Benutzerbild von dizzy
dizzy

Registriert seit: 26. Nov 2003
Ort: Lünen
1.932 Beiträge
 
Delphi 7 Enterprise
 
#1

Prozedur-Parameter mit variantem Typ?

  Alt 19. Mai 2004, 21:06
Hallo geschätzte Mit-Delphianer!

Mir stellt sich soeben folgendes Problem:
Ich habe in meiner Parserklasse eine Prozedur, die das Zerlegen eines Strings vornimmt. Nun kann mein Parser mit reellen Zahlen, komplexen, und Quaternionen rechnen. Um ihm mitzuteilen, welchen Zahlentyp man nun benutzen möchte, muss eine entsprechende Property gesetzt werden.
Der String-Zerleger baut die resultierende Formel in einen Baum um - und die Knoten (eigene Klassen) sind nun vom verwendeten Zahlenformat abhängig.
D.h.:
Code:
reelle Zahlen : Knoten sind der Klasse T[b]R[/b]Node
komplexe Zahlen: Knoten sind der Klasse T[b]C[/b]Node
Quaternionen  : Knoten sind der Klasse T[b]Q[/b]Node
Also habe ich derzeit gleich DREI Prozeduren die, je nach Zahlenformat, in einen entsprechenden Baum parsen. Und da diese Prozeduren sehr ähnlich sind, und zu dem recht lang, fände ich es jetzt eleganter daraus EINE zu machen.
Sie sind wie folgt deklariert:
procedure TCQParser.TTR(s: string; var currentND: TQNode); s ist der zu parsende String, und currentND ist der Kandidat um den es geht. Er ist in diesem Bsp. vom Typ TQNode, es handelt sich also um die Prozedur die den Baum für eine Formel mit Quaternionen aufbaut. Es gibt die gleichen Deklarationen noch 2 mal, nur mit dem Unterschied, dass "currentND" anderen Typs ist.
IN der Prozedur ändert sich eigentlich nur folgendes:
Delphi-Quellcode:
// ein:
  currentND := TQNode.Create(addQ);
// wird bei der Version mit Quaternionen geschrieben, aber
  currentND := TCNode.Create(addC);
// bei der Version mit komplexen Zahlen, und
  currentND := TRNode.Create(opAdd);
// bei reellen Zahlen
Die Parameter die im Create übergeben werden sind in den ersten beiden Fällen Pointer auf eine Function, und im dritten Fall ein Set-Element.

Die Frage ist also, ob ich "currentND" irgendwie sinnvoll SO angeben kann, so dass ich im Rumpf dann komfortabel auf den EIGENTLICHEN Typ reagieren kann. Komfortabel deswegen, weil diese "currentND := ..."-Zeilen ca. 25-30 mal in der Prozedur auftauchen, und es soll noch mehr werden
Einen untypisierten Pointer würde ich zu gerne vermeiden, da ich möglichts D8-Kompatibel arbeiten möchte. (Ich hab D8 zwar nicht, aber ich meine gelesen zu haben, dass untyp. Pointer dort nicht drin sind...)


Im gleichen Zuge ist das Problem vorhanden, dass ich dem Parser die Möglichkeit eingeräumt habe 8 Variablen zu unterstützen, deren Änderung ohne neues Parsen wirken. Dazu habe ich bei der Deklaration der Klasse 8 public-Variablen. Nun können die aber 3 verschiedene Typen haben: TQuat, TComplex oder double.
Also habe ich 3x8 Variablen:
Ar, Br, Cr, ... für reelle Zahlen
Ac, Bc, Cc, ... für komplexe Zahlen und so weiter.
Ich würde aber viel lieber einfach A, B, C, ... einrichten, und der Typ soll sich nach dem vorbestimmten Nummernformat richten.
So sieht's z.Zt. aus:
Delphi-Quellcode:
  TNumFormat = (nfReal, nfComplex, nfQuaternion);

  TCQParser = class(TObject)
  private
    rootR: TRNode;
    rootC: TCNode;
    rootQ: TQNode;
    procedure FlushTrees;
    procedure TTR(s: string; var currentND: TRNode); overload;
    procedure TTR(s: string; var currentND: TCNode); overload;
    procedure TTR(s: string; var currentND: TQNode); overload;
  public
    // grausig hier... :)
    Ar, Br, Cr, Dr, Er, Fr, Gr, Hr: double;
    Ac, Bc, Cc, Dc, Ec, Fc, Gc, Hc: TComplex;
    Aq, Bq, Cq, Dq, Eq, Fq, Gq, Hq: TQuat;
    NumberFormat: TNumFormat;
    procedure Parse(s: string);
    procedure Solve(var res: double); overload;
    procedure Solve(var res: TComplex); overload;
    procedure Solve(var res: TQuat); overload;
    constructor Create;
    destructor Destroy; override;
  end;

Ich habe das jetzt mal zusammen in diesen Thread gepackt, da ich schätze, dass das artverwandte Probleme sind. Falls das Murks war sagt nur fix bescheid - dann teile ich das gerne auf



Danke euch schonmal brühwarm,
dizzy
Fabian K.
INSERT INTO HandVonFreundin SELECT * FROM Himmel
  Mit Zitat antworten Zitat
Christian Seehase
(Co-Admin)

Registriert seit: 29. Mai 2002
Ort: Hamburg
11.262 Beiträge
 
Delphi 2006 Professional
 
#2

Re: Prozedur-Parameter mit variantem Typ?

  Alt 19. Mai 2004, 21:19
Moin Dizzy,

nach Aussen hin könntest Du das evtl. dadurch auf einen Typ zurückführen, indem Du eine Basisklasse dafür erstellst (z.B. TBaseNode genannt), von der aus Du dann die drei gewünschten ableitest (z.B. TQNode = class(TBaseNode)).
Jetzt kannst Du als Parametertypen TBaseNode angeben und innerhalb der Methode mit is den Typ ermitteln, bzw. mit as verwenden.
Tschüss Chris
Die drei Feinde des Programmierers: Sonne, Frischluft und dieses unerträgliche Gebrüll der Vögel.
Der Klügere gibt solange nach bis er der Dumme ist
  Mit Zitat antworten Zitat
Benutzerbild von dizzy
dizzy

Registriert seit: 26. Nov 2003
Ort: Lünen
1.932 Beiträge
 
Delphi 7 Enterprise
 
#3

Re: Prozedur-Parameter mit variantem Typ?

  Alt 19. Mai 2004, 21:27
An sich keine üble Idee. Mir schien das zunächst komisch, da die Basisklasse identisch zu TObject wäre, da ins Besondere TRNode völlig anders aussieht, als die anderen beiden. Aber hast Recht! So könnte man dran gehen. Dann wird das aber ein irres Rumgecaste im Prozedurrumpf, und die ohne hin schon sehr oft vorkommenden "if's" werden halt noch ein paar mehr
(Im Grunde ist der Rumpf fast nur eine riesige "if..then..else if..then..else usw.usf."-Geschichte *g* Das sieht dann nachher funky aus )


Ich mach mich gleich mal dran!
gruss,
dizzy
Fabian K.
INSERT INTO HandVonFreundin SELECT * FROM Himmel
  Mit Zitat antworten Zitat
Benutzerbild von dizzy
dizzy

Registriert seit: 26. Nov 2003
Ort: Lünen
1.932 Beiträge
 
Delphi 7 Enterprise
 
#4

Re: Prozedur-Parameter mit variantem Typ?

  Alt 19. Mai 2004, 21:44
Uffa!

Damit mache ich mir aus einem 3-Zeiler einen 20-Zeiler:
Vorher: (für den reellen Modus)
Delphi-Quellcode:
currentND := TRNode.Create(opAdd);
TTR(anfang(s,'+'), currentND.subNodes[0]);
TTR(ende(s,'+'), currentND.subNodes[1]);
Nachher: (universal mit TObject als "Knotencontainer")
Delphi-Quellcode:
if currentND is TRNode then
begin
  currentND := TObject(TRNode.Create(opAdd));
  TTR(anfang(s,'+'), TObject(TRNode(currentND).subNodes[0]));
  TTR(ende(s,'+'), TObject(TRNode(currentND).subNodes[1]));
end
else
if currentND is TCNode then
begin
  currentND := TObject(TCNode.Create(addC));
  TTR(anfang(s,'+'), TObject(TCNode(currentND).subNodes[0]));
  TTR(ende(s,'+'), TObject(TCNode(currentND).subNodes[1]));
end
else
if currentND is TQNode then
begin
  currentND := TObject(TQNode.Create(addQ));
  TTR(anfang(s,'+'), TObject(TQNode(currentND).subNodes[0]));
  TTR(ende(s,'+'), TObject(TQNode(currentND).subNodes[1]));
end;
Und solche Teile stehen dann satte 28 Mal untereinander... Das hier war ja nur für den Fall, dass ein "+" gefunden wurde. Da kommt noch -,*,/,^ und das ganze Sinus-Cosinuns-Zeug und die 8 (naja eigentlich 24) Variablen, UND der Fall, dass eine reine Zahl als Konstante im String steht...
Bisher habe ich also diese 28*3-Zeiler 3 Mal (für jeden Zahlentyp ein Mal), und mit der obigen Änderung käme ich nicht auf eine Verdreifachung an Zeilen, sondern auf eine Verzwanzigfachung Ganz zu schweigen von dem irren Gecaste, das der Übersichtlichkeit ja noch mehr ans Bein pinkelt
Rein technisch sicherlich eine machbare Lösung - aber mein Ziel, die Übersichtlichkeit und Eleganz zu verbessern - erreiche ich fürchte ich SO nicht :\
Kann man da nicht etwas (sehr) komfortabler dran gehen?


gruss,
dizzy


\\edit:
Oder fragen wir anders: Kann man in Klassendeklarationen evtl. ähnlich vorgehen wie bei varianten Records??
Quasi:
Delphi-Quellcode:
  TNumFormat = (nfReal, nfComplex, nfQuaternion);

  TCQParser = class(TObject)
  private
    rootR: TRNode;
    rootC: TCNode;
    rootQ: TQNode;
    procedure FlushTrees;
    // sowas in der Art?
    case NumberFormat of
      nfReal: procedure TTR(s: string; var currentND: TRNode); overload;
      nfComplex: procedure TTR(s: string; var currentND: TCNode); overload;
      nfQuaternion: procedure TTR(s: string; var currentND: TQNode); overload;
    end;
    //------------------
  public
    // grausig hier... :)
    Ar, Br, Cr, Dr, Er, Fr, Gr, Hr: double;
    Ac, Bc, Cc, Dc, Ec, Fc, Gc, Hc: TComplex;
    Aq, Bq, Cq, Dq, Eq, Fq, Gq, Hq: TQuat;
    NumberFormat: TNumFormat;
    procedure Parse(s: string);
    procedure Solve(var res: double); overload;
    procedure Solve(var res: TComplex); overload;
    procedure Solve(var res: TQuat); overload;
    constructor Create;
    destructor Destroy; override;
  end;
Dass es genau so NICHT geht, hab ich schon bemerkt Aber könnte man so etwas ähnliches basteln?
Fabian K.
INSERT INTO HandVonFreundin SELECT * FROM Himmel
  Mit Zitat antworten Zitat
Tryer

Registriert seit: 16. Aug 2003
200 Beiträge
 
#5

Re: Prozedur-Parameter mit variantem Typ?

  Alt 19. Mai 2004, 21:56
Vielleicht ginge es komfortabler wenn Du komplett auf Variant-Typen umstellst.
Für komplexe Zahlen findest Du einen Variant-Typ in der Unit VarCmplx.
Dein TQuad müsstest Du als class(TCustomVariantType) implementieren, das sollte aber dank der recht ausführlichen Hilfe und dem Beispiel aus VarCmplx nicht allzu schwierig sein (den Aufwand kann ich allerdings nicht abschätzen).

MfG,
Tryer
  Mit Zitat antworten Zitat
Benutzerbild von dizzy
dizzy

Registriert seit: 26. Nov 2003
Ort: Lünen
1.932 Beiträge
 
Delphi 7 Enterprise
 
#6

Re: Prozedur-Parameter mit variantem Typ?

  Alt 19. Mai 2004, 22:08
Ausgeschlossen. Die eigentlichen Berechungs-Funktionen für komplexe Zahlen/Quats habe ich z.T. mit asm "verschnellert".* Ich bin sau-froh, dass ich das hinbekommen hab. Ich glaube ich will keine Variants mit asm selber behandeln müssen *g*. Zudem ist der Datentyp mit Sicherheit recht langsam, und das würde den gesamten Parser ganz kräftig in den Keller ziehen (ist auf Perfomance ausgelegt). Zumal das eigentliche Problem ja beim Parsen selbst besteht - sobald der Baum fertig ist, ist alles klaro. Aber in eben diesen Baum würde ich damit dann ja ganz massiv eingreifen, obwohl es (hoffentlich) nicht nötig ist...
Und: Zu diesem Projekt sind jetzt schon etwas unter 3000 Zeilen Code geschrieben, davon ca. 1700 NUR für die Funktionen wie addQ, addC usw., die also die Basis für den Parser bilden. DAS ALLES wieder komplett über den Haufen schmeissen... ne. Also so lieb das von dir gemeint ist -> nö

Zur Not muss ich's so lassen. Ich find's net schön, aber wenn sich kein (machbarer) Weg findet, muss ich damit leben
Wie schauts denn mit der Variablen-Geschichte in der Klassendeklaration aus? Kann man nicht wenigstens dort mit wenig Schnickschnak was nettes "drehen"?


Danke nochmals! (Und ich kannte diesen Variant-Typ noch nicht mals... )


*Es gibt die gleiche Unit sogar 2 Mal. Einmal MIT asm, und einmal OHNE. Also hier schon doppelter Aufwand das umzuschreiben... ich hab Angst *g*
Fabian K.
INSERT INTO HandVonFreundin SELECT * FROM Himmel
  Mit Zitat antworten Zitat
Chewie

Registriert seit: 10. Jun 2002
Ort: Deidesheim
2.886 Beiträge
 
Turbo Delphi für Win32
 
#7

Re: Prozedur-Parameter mit variantem Typ?

  Alt 19. Mai 2004, 22:24
Ich hab jetzt deinen Code nicht groß angesehen, aber wenn du die Berechnungen nach außen hin in gleichlautenden, gleichparametrigen virtuellen Methoden kapselst, sparst du dir das Gecaste, da das der Compiler dann für dich übernimmt. Da ich wie gesagt deinen Code nur überflogen hab (ich sollte mal so langsam ins Bett *gähn*), weiß ich natürlich nicht, ob dir das was bringt.
Martin Leim
Egal wie dumm man selbst ist, es gibt immer andere, die noch dümmer sind
  Mit Zitat antworten Zitat
Benutzerbild von dizzy
dizzy

Registriert seit: 26. Nov 2003
Ort: Lünen
1.932 Beiträge
 
Delphi 7 Enterprise
 
#8

Re: Prozedur-Parameter mit variantem Typ?

  Alt 19. Mai 2004, 22:34
Zitat von Chewie:
[...] nach außen hin in gleichlautenden, gleichparametrigen virtuellen Methoden kapselst, [...]
Genau dort liegt ja der Hund begraben... Die 3 Parser-Methoden kommen gerade deswegen zu Stande, weil die Addition von zwei komplexen Zahlen nun mal zwei komplexe Operanden als zu verrechnend erwartet - die von 2 Quaternionen TQuats. Und gerade die Implementierung der "normalen" reellen Zahlen unterscheidet sich sehr groß von den anderen beiden Varianten. Eben so, dass jede für sich so performant wie möglich ablaufen kann.
Ich möchte nur sehr sehr ungerne an den eigentlichen Typen drehen, sondern viel lieber an ihrer Deklaration bei der Übergabe zwischen den Prozeduren
Fabian K.
INSERT INTO HandVonFreundin SELECT * FROM Himmel
  Mit Zitat antworten Zitat
Tryer

Registriert seit: 16. Aug 2003
200 Beiträge
 
#9

Re: Prozedur-Parameter mit variantem Typ?

  Alt 19. Mai 2004, 23:15
Das Du nich alles auf Variants umstellen willst kann ich verstehen, der Aufwand wäre dann wirklich enorm. Komfort vs. Performance, da gibts halt wenig Kompromisse

Mal nen Schnellschuss zu den Variablen:
Double, TComplex und TQuat sollten sich doch auf das folgende TNumber casten lassen (was dann bei jeder Zuweisung nötig wäre)
Delphi-Quellcode:
type
  TNumber = array [0..0] of Double;
  
  TDummy = class
  protected
    procedure SetVariable(VarName: string; const Value: TNumber);
    function GetVariable(VarName: string): TNumber;
  public
    NumberFormat: TNumberFormat;
    property Variable[VarName: string]: TNumber read GetVariable write SetVariable;
  end;
Ohne gemeinsame Basisklasse für die Variablen sehe ich keine andere Chance um sie unter einen Hut zu bekommen.

MfG,
Tryer
  Mit Zitat antworten Zitat
Christian Seehase
(Co-Admin)

Registriert seit: 29. Mai 2002
Ort: Hamburg
11.262 Beiträge
 
Delphi 2006 Professional
 
#10

Re: Prozedur-Parameter mit variantem Typ?

  Alt 19. Mai 2004, 23:27
Moin Dizzy,

warum case?

Overload alleine sollte genügen.
Tschüss Chris
Die drei Feinde des Programmierers: Sonne, Frischluft und dieses unerträgliche Gebrüll der Vögel.
Der Klügere gibt solange nach bis er der Dumme ist
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 3  1 23   

Themen-Optionen Thema durchsuchen
Thema durchsuchen:

Erweiterte Suche
Ansicht

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 20:59 Uhr.
Powered by vBulletin® Copyright ©2000 - 2020, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2020 by Daniel R. Wolf