Delphi TStringList inkompatibel mit FPC TStringList?

Für Fragen von Einsteigern und Programmieranfängern...
Antworten
Nimral
Beiträge: 390
Registriert: Mi 10. Jun 2015, 11:33

Delphi TStringList inkompatibel mit FPC TStringList?

Beitrag von Nimral »

Blöderweise habe ich kein Delphi mehr am Start.

Dieses Snippet stammt aus einem Code Sample zu Synapse.

Code: Alles auswählen

const
  StrPropNames: array[0..12] of string=(
    'Content-Type',             // 0
    'Content-Type',             // 1
    'Content-Disposition',      // 2
    'Content-Disposition',      // 3
    'Location',                 // 4
    'Etag',                     // 5
    'Host',                     // 6
    'Referer',                  // 7
    'User-Agent',               // 8
    'Vary',                     // 9
    'WWW-Authenticate',         //10   //!!!TODO
    'Authorization',            //11
    'Content-Type'              //12
  );

function THttpRequest.GetStrProp(Index: integer): string;
var p: integer;
begin
  Result:='';
  if (Index>=0) and (Index<=High(StrPropNames)) then begin
    Result:=Headers[StrPropNames[Index]];	 // SynHttpSrv.pas(1959,32) Error: Incompatible type for arg no. 1: Got "AnsiString", expected "LongInt"
    //
    case Index of
      1: begin
        // BaseContentType... remove sub-type...
        p:=Pos(';',Result);
        if (p>0) then
          Result:=TrimCopy(Result,1,p-1);
      end;
      3: begin
        // TargetFileName, extract it:
        // Content-Disposition: attachment; filename="Filename"    also works without the "attachment"...
        Result:=GetHeaderSubValue(Result,'filename')
      end;
      12: begin
        // Boundary:
        Result:=GetHeaderSubValue(Result,'boundary');
      end;
    end;
  end;
end; 
Headers ist als TStringList deklariert. Da versucht also jemand, mit einem String als Index zuzugreifen - was genau soll das bewirken. Ich habe die Delphi Doks hoch und runter durchsucht, eine solche Anwendung von TStringList findet sich da nicht.

Armin.

Benutzeravatar
theo
Beiträge: 10497
Registriert: Mo 11. Sep 2006, 19:01

Re: Delphi TStringList inkompatibel mit FPC TStringList?

Beitrag von theo »

Nimral hat geschrieben:
Mo 20. Dez 2021, 10:32
Headers ist als TStringList deklariert.
Nö, ist als THeaderList deklariert.

https://github.com/Makhaon/SynHTTP/blob ... ttpSrv.pas

Nimral
Beiträge: 390
Registriert: Mi 10. Jun 2015, 11:33

Re: Delphi TStringList inkompatibel mit FPC TStringList?

Beitrag von Nimral »

Stimmt :-) Abgeleitet von TStringList, aber da gibt es noch mehr :-)

Code: Alles auswählen

type
  // Result: True=found/stop, False=continue
  THeaderEnum=function(const Value: string; LParam: Longint): Boolean of object;
  
  THeaderList=class(TStringList)
  protected
    { Internal methods: }
    function GetValueByName(const Name: string):string;
    procedure SetValueByName(const Name,Value: string);
    function GetNameByIndex(Index: integer): string;
    function GetValueByIndex(Index: integer): string;
    function CheckHttpFindValue(const Value: string; LParam: Longint): Boolean;
    function GetSubValue(const Name,SubName: string): string;
    procedure SetSubValue(const Name,SubName,Value: string);
  public
    { Internal methods: }
    function Add(const S: string): integer; override;
    procedure Insert(Index: integer; const S: string); override;
    procedure Put(Index: integer; const S: string); override;
  public
    property Values[const Name: string]: string read GetValueByName write SetValueByName; default;
    //
    property Strings;
    property Names[Index: integer]: string read GetNameByIndex;
    property ValuesByIndex[Index: integer]: string read GetValueByIndex;
    property SubValues[const Name,SubName: string]: string read GetSubValue write SetSubValue; // for 'ContentType: text/html; charset="Windows-1250"', SubValues['Content-Type','charset']
    //
    function IndexOfName(const Name: string): integer;
    procedure AddValue(const Name,Value: string); // add (possibly duplicate) value...
    function RemoveValue(const Name: string): Boolean; // used also by writing Values[Name]:='';
    //
    // Enumerates duplicated or comma-separated headers:
    procedure EnumHeaders(const Name: string; const Enum: THeaderEnum; LParam: Longint=0);
    function  HasValue(const Name,Value: string): Boolean; // Connection: upgrade, close
  end;
Ich kenne dieses Konstrukt bisher nicht, aber es scheint, dass

Code: Alles auswählen

property Values[const Name: string]: string read GetValueByName write SetValueByName; default;
dafür verantwortlich ist. Gibt es dieses Konstrukt unter Lazarus gar nicht?

wp_xyz
Beiträge: 4889
Registriert: Fr 8. Apr 2011, 09:01

Re: Delphi TStringList inkompatibel mit FPC TStringList?

Beitrag von wp_xyz »

Nimral hat geschrieben:
Mo 20. Dez 2021, 11:09
es scheint, dass

Code: Alles auswählen

property Values[const Name: string]: string read GetValueByName write SetValueByName; default;
dafür verantwortlich ist. Gibt es dieses Konstrukt unter Lazarus gar nicht?
Doch:

Code: Alles auswählen

program Project1;
uses
  Classes;
var
  L: TStringList;
begin
  L := TStringList.Create;
  try
    L.NameValueSeparator := ':';  // Default ist: '='
    L.Add('Content-Type:text/html');
    L.Add('User-Agent:Mozilla/5.0');
    WriteLn(L.Values['Content-Type']);
    WriteLn(L.Values['User-Agent']);
  finally
    L.Free;
  end;
  
  ReadLn;
end.

Nimral
Beiträge: 390
Registriert: Mi 10. Jun 2015, 11:33

Re: Delphi TStringList inkompatibel mit FPC TStringList?

Beitrag von Nimral »

Rätselhaft. Der Fehler kostet mich schon den ganzen Morgen.

In der Definition von THeaderList finde ich keinen Fehler, der Compiler auch nicht, trotzdem scheint er die Zeile mit dem "Default" nicht zu akzeptieren. Ich habe dann den Code auf eine Mini-Demo eingedampft:

Code: Alles auswählen

unit Unit1;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, Forms, Controls, Graphics, Dialogs;

type
  TForm1 = class(TForm)
  private

  public

  end;

type
  THeaderList=class(TStringList)
  protected
    { Internal methods: }
    function GetValueByName(const Name: string):string;
    procedure SetValueByName(const Name,Value: string);
  public
    property Values[const Name: string]: string read GetValueByName write SetValueByName; default;
    property Strings;
    //
  end;

var
  Form1: TForm1;

implementation

{$R *.lfm}

function THeaderList.GetValueByName(const Name: string): string;

begin
  Result:='';
end;

procedure THeaderList.SetValueByName(const Name,Value: string);

begin
end;

Procedure Test;

var
    S:String;
    T:THeaderList;

begin
     T := THeaderList.Create;
     S:=T['Expect'];
     FreeAndNil(T);
end;

end.
Er compiliert nicht:
2021-12-20 12_13_34-.png
2021-12-20 12_13_34-.png (43.31 KiB) 1261 mal betrachtet
Und dann der Hammer: sobald ich Zeile 26 (property Strings;) auskommentiere, verschwindet die Fehlermeldung. Ich kann die Property auch in eine eigene Public Sektion setzen, auch dann geht es.

Code: Alles auswählen

type
  THeaderList=class(TStringList)
  protected
    { Internal methods: }
    function GetValueByName(const Name: string):string;
    procedure SetValueByName(const Name,Value: string);

  public
    property Strings;

  public
    property Values[const Name: string]: string read GetValueByName write SetValueByName; default;

    //
  end;
Ich darf die Property aber nicht hinter die property Values setzen, auch nicht private oder protected, sobald ich das mache ist der Compilerfehler wieder da. Sie muss also oberhalb von property Values[....] stehen.

Wtf???

Armin

P.S. Die Originaldatei ist übrigens SynHTTPSrv.pas aus der SynHTTP Demo von Synapse.
Dateianhänge
unit1.pas
(927 Bytes) 48-mal heruntergeladen

Benutzeravatar
fliegermichl
Lazarusforum e. V.
Beiträge: 1435
Registriert: Do 9. Jun 2011, 09:42
OS, Lazarus, FPC: Lazarus Fixes FPC Stable
CPU-Target: 32/64Bit
Wohnort: Echzell

Re: Delphi TStringList inkompatibel mit FPC TStringList?

Beitrag von fliegermichl »

Die Default Property von TStrings ist Items. Da ist der Index Integer.
Scheinbar ignoriert der Compiler das Statement Default bei THeaderList.

Schreibt man

Code: Alles auswählen

S := T.Values['Expect'];
Dann akzeptiert er es.

Edit: Er hätte es aber akzeptieren müssen. Aus der Doku:

Only one default property per class is allowed, but descendent classes can redeclare the default property.

So würde ich sagen, es ist ein Compiler Bug.

Socke
Lazarusforum e. V.
Beiträge: 3158
Registriert: Di 22. Jul 2008, 19:27
OS, Lazarus, FPC: Lazarus: SVN; FPC: svn; Win 10/Linux/Raspbian/openSUSE
CPU-Target: 32bit x86 armhf
Wohnort: Köln
Kontaktdaten:

Re: Delphi TStringList inkompatibel mit FPC TStringList?

Beitrag von Socke »

fliegermichl hat geschrieben:
Mo 20. Dez 2021, 13:28
Die Default Property von TStrings ist Items. Da ist der Index Integer.
Du hast da einen Tippfehler. TStrings.Strings ist die Default Property (Items ist bei mir gar nicht vorhanden).

Der Compiler hat m.E. keinen Fehler. Er nimmt diejenige Property als "default", die zuletzt deklariert wird.

Wird "Strings" nach "Values" nochmals deklariert, wird es Default Property. Inhaltlich bringt das nichts, da die Deklaration nicht verändert wird und auch in TStringList bereits public ist.

Code: Alles auswählen

  public
    property Values[const Name: string]: string read GetValueByName write SetValueByName; default;
    property Strings;
Wird "Strings" vor "Values" (re-)deklariert, wird "Values" die Default Propery. Ob das in einem eigenen oder im selben Abschnitt ist, spielt keine Rolle.
MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein

PascalDragon
Beiträge: 830
Registriert: Mi 3. Jun 2020, 07:18
OS, Lazarus, FPC: L 2.0.8, FPC Trunk, OS Win/Linux
CPU-Target: Aarch64 bis Z80 ;)
Wohnort: München

Re: Delphi TStringList inkompatibel mit FPC TStringList?

Beitrag von PascalDragon »

Nimral hat geschrieben:
Mo 20. Dez 2021, 12:27
Wtf???
Der Compiler unterstützt aktuell kein Überladen von Default-Eigenschaften, was jedoch Delphi kann (und Strings ist die Default-Eigenschaft von TStringList). Deswegen gewinnt da aktuell die letzte Eigenschaft, die in der Klasse deklariert ist.
FPC Compiler Entwickler

Benutzeravatar
fliegermichl
Lazarusforum e. V.
Beiträge: 1435
Registriert: Do 9. Jun 2011, 09:42
OS, Lazarus, FPC: Lazarus Fixes FPC Stable
CPU-Target: 32/64Bit
Wohnort: Echzell

Re: Delphi TStringList inkompatibel mit FPC TStringList?

Beitrag von fliegermichl »

Socke hat geschrieben:
Mo 20. Dez 2021, 13:51
fliegermichl hat geschrieben:
Mo 20. Dez 2021, 13:28
Die Default Property von TStrings ist Items. Da ist der Index Integer.
Du hast da einen Tippfehler. TStrings.Strings ist die Default Property (Items ist bei mir gar nicht vorhanden).
Stimmt, Items ist die Default Property von TList.

Nimral
Beiträge: 390
Registriert: Mi 10. Jun 2015, 11:33

Re: Delphi TStringList inkompatibel mit FPC TStringList?

Beitrag von Nimral »

Ok. Ich habs dank euch endlich gerafft. Dass da ein zwei Klassenebenen weiter oben deklariertes "default" einschlägt ... darauf muss man erst mal kommen.

Jetzt noch die Folgefrage: warum hat "Semi" die property Strings überschrieben, und dann aber offenbar keinerlei Gebrauch davon gemacht? Kann ich die Property einfach löschen, sollte ich sie "sicherheitshalber" einfach nach oben schieben, oder bekomme ich dann in irgendeinem Grenzfall wieder eins auf die Nase? Ist das vielleicht etwas was man für Delphi machen muss, etwa wenn man es sich bei der "default" property irgendwo weiter unten in der Vererbung anders überlegt?

Hat jemand eine Idee?

Armin.

Benutzeravatar
fliegermichl
Lazarusforum e. V.
Beiträge: 1435
Registriert: Do 9. Jun 2011, 09:42
OS, Lazarus, FPC: Lazarus Fixes FPC Stable
CPU-Target: 32/64Bit
Wohnort: Echzell

Re: Delphi TStringList inkompatibel mit FPC TStringList?

Beitrag von fliegermichl »

Strings liefert den gesamten Eintrag eines Index.

Code: Alles auswählen

var sl : THeaderList;
begin
 sl := THeaderlist.Create;
 sl.Add('Expect=what?');
 sl.Add('ExpectFurther=whatelse');
 writeln(sl[0]); // Gibt "Expect=what?" aus
 writeln(sl.Values['Expect']); // gibt "what?" aus
 sl.Free; // soviel Zeit muss sein
end;

Antworten