Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Prozedur-Parameter mit variantem Typ? (https://www.delphipraxis.net/22602-prozedur-parameter-mit-variantem-typ.html)

dizzy 19. Mai 2004 21:06


Prozedur-Parameter mit variantem Typ?
 
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:
Delphi-Quellcode:
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 :zwinker:



Danke euch schonmal brühwarm,
dizzy

Christian Seehase 19. Mai 2004 21:19

Re: Prozedur-Parameter mit variantem Typ?
 
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.

dizzy 19. Mai 2004 21:27

Re: Prozedur-Parameter mit variantem Typ?
 
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

dizzy 19. Mai 2004 21:44

Re: Prozedur-Parameter mit variantem Typ?
 
:shock: 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? :gruebel:


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 :cry: Aber könnte man so etwas ähnliches basteln?

Tryer 19. Mai 2004 21:56

Re: Prozedur-Parameter mit variantem Typ?
 
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

dizzy 19. Mai 2004 22:08

Re: Prozedur-Parameter mit variantem Typ?
 
:mrgreen: 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ö :zwinker:

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... :stupid: )


*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*

Chewie 19. Mai 2004 22:24

Re: Prozedur-Parameter mit variantem Typ?
 
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.

dizzy 19. Mai 2004 22:34

Re: Prozedur-Parameter mit variantem Typ?
 
Zitat:

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 :?

Tryer 19. Mai 2004 23:15

Re: Prozedur-Parameter mit variantem Typ?
 
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

Christian Seehase 19. Mai 2004 23:27

Re: Prozedur-Parameter mit variantem Typ?
 
Moin Dizzy,

warum case?

Overload alleine sollte genügen.

dizzy 20. Mai 2004 00:05

Re: Prozedur-Parameter mit variantem Typ?
 
Zitat:

Zitat von Tryer
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 ;)

Ja leider... Ich versuch da grad nen vertretbaren Mittelweg zu finden :)

Zitat:

Zitat von Tryer
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

Das sieht an sich schon mal ganz nett aus; zumal ich dieses Konstrukt bei den properties noch nie gesehen hab! Das geht? Oder ist das Pseudocode?
Dann müsste ich zwar trotzdem an meinen Typen TComplex und TQuat drehen (die sind z.Zt. nen record und kein array), aber das könnte gehen, so denn der Cast klappt! Einziger kleiner Nachteil: Das Berechnen des Baumes mit reellen Zahlen dürfte langsamer werden. Hab dann ja keinen nativen Datentyp mehr, sondern "nur" Zeiger drauf, oder guck ich komisch? ;)
Aber das ließe sich evtl. verschmerzen. Im Moment ist der Parser bei double-Typen ca. 0,6 Mal so schnell wie eine hardgecodete Berechnung. Das ist gut genug, um davon ein klein wenig abzugeben :) (Wenn ich das jetzt total missverstanden hab, dann schrei ganz laut - ich geh' dann in die Ecke, gell!?)


@Christian: Naja, aber das overload; ist ja genau das Gegenteil von dem was ich gerne hätte. Ich möchte ja eine Implementierung mit mehreren möglichen Deklarationen, und nicht mehrere Prozedurrümpfe, jeweils für einen Fall gesondert :zwinker:
Oder hab ich dich verstanden Mist?


grüzli,
dizzy

Christian Seehase 20. Mai 2004 00:12

Re: Prozedur-Parameter mit variantem Typ?
 
Moin Dizzy,

nein, Du hast mich nicht mistverstanden ;-)

Das Problem ist nur:
Entweder Du fasst alles in einer, dann entsprechend umfangreichen, Methode zusammen, oder Du teilst es auf spezialisierte Methoden auf.
Letzteres hätte den Vorteil, dass Du übersichtlichere Methoden bekommst, und auch leichter noch Datentypen hinzufügen kannst, soweit erforderlich. Vermutlich wäre diese Variante auch schneller, mit Sicherheit aber leichter zu warten/debuggen.

Nachteil:
Redundanter Code.

Tryer 20. Mai 2004 00:21

Re: Prozedur-Parameter mit variantem Typ?
 
Casting und Pseudocode werden so auch funktionieren. Du brauchst in der Deklaration nicht von Record auf Array umsteigen. Beim Zugriff auf das statische Array wird ja sozusagen direkt auf´s erste Element zugegriffen. Für Records gilt die gleiche Zugriffsweise. Der sicherheit halber würde ich aber vielleicht noch TNumber und die Records als packed deklarieren.

Innerhalb der Get/Set-Routinen solltest Du dann natürlich abhängig vom NumericFormat das ganze in den "richtigen" Datenstrukturen ablegen, aber nach aussen erscheint alles als TNumber.

Die Property an sich ist nichts besonderes:
Canvas.Pixels[X, Y: Integer]
List.Items[Index: Integer]
TStringsList.Value[Name: string] (?)
..
Der Index kann also jegliche Form annehmen (z.B. auch ein TVarNames = (A, B, C, D, E, F, ..), einzige Bedingung ist Schreib-und Lesezugriff als Methode bereitzustellen (ein direkter Feldzugriff auf "FNumber" könnte natürlich nicht zugeordnet werden.

MfG,
Tryer

dizzy 20. Mai 2004 00:30

Re: Prozedur-Parameter mit variantem Typ?
 
Zitat:

Zitat von Christian Seehase
[..] übersichtlichere Methoden
[..] leichter noch Datentypen hinzufügen
[..] auch schneller
[..] leichter zu warten/debuggen

Nachteil:
Redundanter Code.

Ich glaube, du hast mich überzeugt :mrgreen:

Ich lass es dann zunächst so, wie es ist. Das mit den Variablen habe ich mir gerade auch nochmal durch den Kopf gehen lassen: Es wäre natürlich toll ein und den selben Namen für eine Variable mit variierendem Typ zu haben, weil nur ein Typ gleichzeitig vorkommt - nur was täte man damit einem Programmierer an? Man müsste ständig nachhalten, was man vor 1000 Zeilen Code mal dort reingeschrieben hat - und von welchem Typ das ganze war...
Ich werde das prinzipell mal ausprobieren, was Tryer vorschlug (sieht nämlich irgendwie total elegant aus!), aber ob ich das dann durch meine 3tausend Zeilen Code durchziehe weiss ich noch nicht. Zudem hängen an den Datentypen mittlerweile 3 Programme und 3 Klassen (ausser dem Parser) auch mit insgesammt mehreren tausend Zeilen Code dran :? Tja - die Datentypen verwende ich schon etwas länger in ihrer Form als record - weit länger, als der Parser jetzt existiert :) Das kommt dann davon, wen man nicht von vorne herein alles haarklein planen kann... Mist Freizeitprojekte :lol:


Ganz heissen Dank an euch! Und wenn dann doch noch jemandem was dazu einfällt, dann mal immer her damit...

dizzy 20. Mai 2004 00:34

Re: Prozedur-Parameter mit variantem Typ?
 
Zitat:

Zitat von Tryer
Casting und Pseudocode werden so auch funktionieren. Du brauchst in der Deklaration nicht von Record auf Array umsteigen. Beim Zugriff auf das statische Array wird ja sozusagen direkt auf´s erste Element zugegriffen. Für Records gilt die gleiche Zugriffsweise. Der sicherheit halber würde ich aber vielleicht noch TNumber und die Records als packed deklarieren.

Innerhalb der Get/Set-Routinen solltest Du dann natürlich abhängig vom NumericFormat das ganze in den "richtigen" Datenstrukturen ablegen, aber nach aussen erscheint alles als TNumber.

Die Property an sich ist nichts besonderes:
Canvas.Pixels[X, Y: Integer]
List.Items[Index: Integer]
TStringsList.Value[Name: string] (?)
..
Der Index kann also jegliche Form annehmen (z.B. auch ein TVarNames = (A, B, C, D, E, F, ..), einzige Bedingung ist Schreib-und Lesezugriff als Methode bereitzustellen (ein direkter Feldzugriff auf "FNumber" könnte natürlich nicht zugeordnet werden.

MfG,
Tryer

Ei! Grade erst gesehen! Stimmt... Pixels... ja, da hab ich das auch schon mal gesehen *g*. Mich hat der Typ String als Index so verwundert... aber das ist ja mal nett, dass das geht!

Ich glaube, ich komme jetzt dahinter, wie du das meinst. Das sieht echt gut aus! Da muss ich gleich mal ein wenig fummeln gehen :coder:
(Du bist doch noch länger wach, gelle!? ;) )


Dangöö!

dizzy 20. Mai 2004 00:48

Re: Prozedur-Parameter mit variantem Typ?
 
Der Cast tut nicht. (Ungültige Typumwandlung)
SetVariable:
Delphi-Quellcode:
procedure TCQParser.SetVariable(VarName: TVarName; const Value: TNumber);
begin
  case VarName of
    A: case NumberFormat of
         nfReal     : Ar := double(Value);  // dieser Cast geht
         nfComplex  : Ac := TComplex(Value); // der nicht
         nfQuaternion: Aq := TQuat(Value);   // der auch nicht...
    B: . . .
    .
    .
    .
  end;
end;
Was tun? Steh' grad ein wenig wie Ochs vorm Berg, weil SO abwegig hab ich noch nie gecastet :)


\\edit:
So gehts:
Delphi-Quellcode:
type PNumber = ^TNumber;
.
.
.
procedure TCQParser.SetVariable(VarName: TVarName; const Value: PNumber);
begin
  case VarName of
    A:
    case NumberFormat of
      nfReal     : Ar := Value[0];
      nfComplex  : Ac := PComplex(Value)^;
      nfQuaternion: Aq := PQuat(Value)^;
    end;
    B: . . .
    .
    .
    .
  end;
end;
Sieht völlig geil aus :lol: und funzt!
Schade ist nur, dass man jetzt bei der Zuweisung einer Variablen an eine Instanz des Parsers wie folgt vorgehen muss:
Delphi-Quellcode:
var p: TCQParser;
    q: TQuat;

  q.x := pi/2;
  q.y := 0;
  q.z := 0;
  q.w := 0;
  p.Variable[A] := PNumber(@q);
Das heisst, dass der "user" der Klasse auch noch wie wild casten müsste, und dass immer nur Variablen (im Sinne von Delphi-Variablen jetzt) übergeben werden müssen. Einfach eine 1 ist dann nicht mehr möglich.
Aber Abstriche hat man überall, woll!?
Den Cast bei der Zuweisung würde ich gerne aber noch irgendwie los werden. Kann man das irgendwie bewerkstelligen?


Schonmal einen riesen-Dank! Das klappt soweit!! *froi*
dizzy

Christian Seehase 20. Mai 2004 01:26

Re: Prozedur-Parameter mit variantem Typ?
 
Moin Dizzy,

was hältst Du von dieser Idee die Typen "in einem Rutsch" zu deklarieren:

Delphi-Quellcode:
type
  TNumberType = (ntDouble,ntComplex,ntQuad);

  TNumber = record
    ntType : TNumberType;
    x     : double;
    y     : double;
    z     : double;
    w     : double;
  end;
ich hoffe es ist selbsterklärend ;-)

dizzy 20. Mai 2004 01:44

Re: Prozedur-Parameter mit variantem Typ?
 
Zitat:

Zitat von Christian Seehase
Moin Dizzy,
was hältst Du von dieser Idee die Typen "in einem Rutsch" zu deklarieren:
ich hoffe es ist selbsterklärend ;-)

Japp, ist es :)
Hat seinen Reiz! Ich fürchte nur dass es, wie oben schon mal anklang, dafür schon zu spät ist. Die Änderungen die das nach sich ziehen würde wären ziemlich aufwändig. Das Zuweisungsproblem an sich ist ja jetzt gelöst (du hast gepostet während ich editierte...) - es wäre jetzt halt nur noch schön, wenn der Benutzer des Parsers nicht (wie oben) rum-casten müsste. Sobald das ist, bin ich der glücklichste Parser-Schreiber der Welt - und ihr seid schuld :lol:
(btw: könnten sowas die Jedis brauchen?)


ciao,
dizzy :firejump:

Tryer 20. Mai 2004 01:54

Re: Prozedur-Parameter mit variantem Typ?
 
Jo, tut nicht.. sorry, hab mich da etwas vertan.
Das Konstrukt "array [0..0] of xy" macht in manchen Datenstrukturen Sinn (z.B. wenn ich einen Record als Header habe und da am Ende dann eine variable Datenmenge dranhängen möchte), aber hier hilft es absolut nicht weiter.
Über eine "Double-weise" Zuweisung liesse sich was drehen, aber da der Cast ja von aussen nicht klappt ist das ganze eh sinnlos :oops:

Wenn mir noch ne Lösung einfällt melde ich mich,
:duck: MfG, Tryer

[Edit] Ob das mit dem PNumber unter D8 funzen wird wage ich mal zu bezweifeln, ich vermute das sich die Einschränkung da nicht rein auf untypisierte Pointer begrenzen wird. Ein Casting zwischen Datenstrukturen unterschiedlicher Grösse wird vermutlich unzulässig sein (das wäre ja imo genauso "unsicherer Code":roll: wie ein untypisierter Pointer).[/Edit]

dizzy 20. Mai 2004 02:17

Re: Prozedur-Parameter mit variantem Typ?
 
Öh, äh, üh --- Halt! Stop! Klappt doch alles wunderbar!
Nur muss man beim Zuweisen und Auslesen der Variablen in/aus einer Parserinstanz ordentlich rumcasten. Ansonsten funktioniert das voll und ganz! Und die Geschwindigkeit leidet NULL drunter. Für mich sieht das im Moment nach der Lösung aus :)

\\edit: D8 und Casts: Ach weisst du... dann lass ich datt mit D8. Ich bin jetzt so glücklich mit der Lösung... und Win32 ist ja wohl noch nicht tot ;)

Tryer 20. Mai 2004 09:43

Re: Prozedur-Parameter mit variantem Typ?
 
Hier nochmal eine andere Fassung: Zugriff auf die Variablen über getrennte Get-und Set-Routinen mit typlosem Value (-> ausserhalb kein Casting nötig, aber halt auch kein "property-Zugriff").
Wenn Du bei der vorherigen Lösung bleiben willst dann würde ich das TNumber wieder rausschmeissen und statt dessen mit TQuat arbeiten, da passen die anderen Typen schliesslich auch rein.

Delphi-Quellcode:
type
  TVariableArray = array [TVarNames] of TQuat;

  TDummy = class
  private
    FVars: TVariableArray;
  protected
  public
    NumFormat: TNumFormat;
    procedure SetVariable(VarName: TVarNames; const Value);
    procedure GetVariable(VarName: TVarNames; var Value);
  end;

implementation

{ TVaribles }

procedure TDummy.GetVariable(VarName: TVarNames; var Value);
begin
  case NumFormat of
    nfReal:
      Double(Value) := PDouble(@FVars[VarName])^;
    nfComplex:
      TComplex(Value) := PComplex(@FVars[VarName])^;
    nfQuat:
      TQuat(Value) := FVars[VarName];
  end;
end;

procedure TDummy.SetVariable(VarName: TVarNames; const Value);
begin
  case NumFormat of
    nfReal:
      PDouble(@FVars[VarName])^ := Double(Value);
    nfComplex:
      PComplex(@FVars[VarName])^ := TComplex(Value);
    nfQuat:
      FVars[VarName] := TQuat(Value);
  end;
end;

procedure Test;
var
  Dum: TDummy;
  D: Double;
  C: TComplex;
  Q: TQuat;
begin
  Dum := TDummy.Create;
  Dum.NumFormat := nfReal;
  D := 1.234;
  Dum.SetVariable(A, D);

  Dum.NumFormat := nfComplex;
  C.X := 1.23;
  C.Y := 4.56;
  Dum.SetVariable(B, C);

  Dum.NumFormat := nfQuat;
  Q.X := 1.23;
  Q.Y := 4.56;
  Q.Z := 7.89;
  Q.W := 10;
  Dum.SetVariable(C, Q);
end;
MfG,
Tryer

dizzy 20. Mai 2004 15:01

Re: Prozedur-Parameter mit variantem Typ?
 
Geil geil geil :thuimb: !
Ich hätte ja garnicht zu hoffen gewagt, dass man einen Parameter typenlos deklarieren kann! Drüber seniert hatte ich, es aber schnellstens wieder verworfen, da Delphi ja so typstreng ist :roll: (scheinbar wohl nicht ganz so sehr :) )
Dass der Propertyzugriff flöten geht ist absolut egal. Das ist dann nur eine Frage der Dokumentation - kein Problem! Wow, genau so hatte ich mir das vorgestellt.
Super-duper-heissen Dank! :firejump:


ein glücklicher
dizzy :hello:


\\edit: Nachtrag:
Ich habe jetzt alles so umgebaut wie du vorschlugst --- und es klappt 1A !! So wie ich mir das gewünscht hab. Nochmals vieeeelen Dank :party:
Alleine wäre ich an so einigen Stellen bös hängen geblieben...


Alle Zeitangaben in WEZ +1. Es ist jetzt 14:31 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