Recent

Author Topic: How to use Write/WriteLn functions with record types?  (Read 4758 times)

İbrahim

  • New Member
  • *
  • Posts: 19
How to use Write/WriteLn functions with record types?
« on: August 12, 2018, 01:26:07 pm »
Hi.
I wrote this code with record type (MyString):
Code: Pascal  [Select][+][-]
  1. program Project1;
  2.  
  3. {$IFDEF FPC}
  4.   {$MODE DELPHI}{$H+}
  5. {$ENDIF}
  6.  
  7. type
  8.  
  9.   { MyString }
  10.  
  11.   MyString = record
  12.   private
  13.     _Data : UnicodeString;
  14.  
  15.     function _Getter: UnicodeString;
  16.     procedure _Setter(const Data : UnicodeString);
  17.   public
  18.     class function Create: MyString; overload; static;
  19.     class function Create(const Data : MyString): MyString; overload; static;
  20.     class function Create(const Data : UnicodeString): MyString; overload; static;
  21.  
  22.     property Data: UnicodeString read _Getter write _Setter;
  23.   end;
  24.  
  25. { MyString }
  26.  
  27. function MyString._Getter: UnicodeString;
  28. begin
  29.   Result := _Data;
  30. end;
  31.  
  32. procedure MyString._Setter(const Data: UnicodeString);
  33. begin
  34.   if _Data <> Data then
  35.     _Data := Data;
  36. end;
  37.  
  38. class function MyString.Create: MyString;
  39. begin
  40.   Result._Data := '';
  41. end;
  42.  
  43. class function MyString.Create(const Data: MyString): MyString;
  44. begin
  45.   Result := Data;
  46. end;
  47.  
  48. class function MyString.Create(const Data: UnicodeString): MyString;
  49. begin
  50.   Result._Data := Data;
  51. end;
  52.  
  53. var
  54.   Obj : MyString;
  55. begin
  56.   Obj := MyString.Create('Hello World!');
  57.   WriteLn(Obj.Data);
  58.   ReadLn;
  59. end.
  60.  
This code nice working but I need to use a property like Data to print string data of MyString object or I need a print method. But I want to print MyString object with Write/Ln functions like this:
Code: Pascal  [Select][+][-]
  1. var
  2.   Obj : MyString;
  3. begin
  4.   Obj := MyString.Create('Hello World!');
  5.   // WriteLn(Obj.Data);   -----> This is working.
  6.   WriteLn(Obj); // This is not working, but I want this.
  7.   ReadLn;
  8. end.
  9.  
How can I do that? Thanks.

Thaddy

  • Hero Member
  • *****
  • Posts: 14373
  • Sensorship about opinions does not belong here.
Re: How to use Write/WriteLn functions with record types?
« Reply #1 on: August 12, 2018, 01:31:51 pm »
You can't. is the short answer. You probably CAN with NewPascal (a fork of FPC).
In that case the code should be like this:
Code: Pascal  [Select][+][-]
  1. program Project1;
  2.  
  3. {$IFDEF FPC}
  4.   {$MODE DELPHI}{$H+}
  5. {$ENDIF}
  6.  
  7. type
  8.  
  9.   { MyString }
  10.  
  11.   MyString = record
  12.   private
  13.     _Data : UnicodeString;
  14.  
  15.     function _Getter: UnicodeString;
  16.     procedure _Setter(const Data : UnicodeString);
  17.   public
  18.     class function Create: MyString; overload; static;
  19.     class function Create(const Data : MyString): MyString; overload; static;
  20.     class function Create(const Data : UnicodeString): MyString; overload; static;
  21.  
  22.     property Data: UnicodeString read _Getter write _Setter;default; // note default....this is not (yet?) in FPC. In FPC only for array properties.
  23.   end;
  24.  
  25. { MyString }
  26.  
  27. function MyString._Getter: UnicodeString;
  28. begin
  29.   Result := _Data;
  30. end;
  31.  
  32. procedure MyString._Setter(const Data: UnicodeString);
  33. begin
  34.   if _Data <> Data then
  35.     _Data := Data;
  36. end;
  37.  
  38. class function MyString.Create: MyString;
  39. begin
  40.   Result._Data := '';
  41. end;
  42.  
  43. class function MyString.Create(const Data: MyString): MyString;
  44. begin
  45.   Result := Data;
  46. end;
  47.  
  48. class function MyString.Create(const Data: UnicodeString): MyString;
  49. begin
  50.   Result._Data := Data;
  51. end;
  52.  
  53. var
  54.   Obj : MyString;
  55. begin
  56.   Obj := MyString.Create('Hello World!');
  57.   WriteLn(Obj);
  58.   ReadLn;
  59. end.
Problem is that user HNB (Maciej Izak) who implemented this in NewPascal and the core Freepascal development team have had some arguments, so it is not in FPC (yet?).
I hope that will get better in the future. It is a feature I want too.
BTW: I am slightly bemused by your overloaded create functions..... What are you trying to achieve? Did you know we have record constructors, management operators and the default() intrinsic?

p.s. I think Maciej will comment on this too.
« Last Edit: August 12, 2018, 02:27:45 pm by Thaddy »
Object Pascal programmers should get rid of their "component fetish" especially with the non-visuals.

İbrahim

  • New Member
  • *
  • Posts: 19
Re: How to use Write/WriteLn functions with record types?
« Reply #2 on: August 12, 2018, 04:36:29 pm »
Quote
I am slightly bemused by your overloaded create functions..... What are you trying to achieve? Did you know we have record constructors, management operators and the default() intrinsic?

Actually, I'm using modern C++. I know that FreePascal has record constructors, management operators and default(). But I'm developing my codes compatible with Delphi. Delphi doesn't support these features.
I write my codes like this, if I use C++:
Code: Diff  [Select][+][-]
  1. class MyString
  2. {
  3. private:
  4.   char* _data;
  5. public:
  6.   MyString() { strcpy(_data, ""); }
  7.   MyString(const char* data) { strcpy(_data, data); }
  8.   MyString(const MyString& data) { strcpy(_data, data._data); }
  9.  
  10.   friend ostream& operator<<(ostream& output, const MyString& data)
  11.   {
  12.     output << data._data;
  13.     return output;
  14.   }
  15. };
  16.  
  17. int main()
  18. {
  19.   MyString obj("Hello World!");
  20.   cout << obj << endl;
  21.  
  22.   return 0;
  23. }
  24.  
I'm writting my codes like C++ in Object Pascal. Because I'm going to use object files (wrote with C++) from Object Pascal or Object Pascal codes from C++. So , I need to write OP codes compatible with C++.
What is your best opinion to initialize record types?

hnb

  • Sr. Member
  • ****
  • Posts: 270
Re: How to use Write/WriteLn functions with record types?
« Reply #3 on: August 12, 2018, 09:05:37 pm »
You probably CAN with NewPascal (a fork of FPC).
...
Problem is that user HNB (Maciej Izak) who implemented this in NewPascal and the core Freepascal development team have had some arguments, so it is not in FPC (yet?).
I hope that will get better in the future. It is a feature I want too.
Yes you can do that in NewPascal it is explicitly supported (WriteLn/Write has some special compiler magic for default field too).

Please note that "default" works for now only for fields ("index-less default" properties are not supported yet):

Code: Pascal  [Select][+][-]
  1.   MyString = record
  2.   private
  3.     _Data : UnicodeString default;
  4.     { ... }
  5.   end;

Core team is not much interested in this feature. But I have also good news - I have new extremely useful feature in the way : aspects :)
Checkout NewPascal initiative and donate beer - ready to use tuned FPC compiler + Lazarus for mORMot project

best regards,
Maciej Izak

hnb

  • Sr. Member
  • ****
  • Posts: 270
Re: How to use Write/WriteLn functions with record types?
« Reply #4 on: August 12, 2018, 09:23:54 pm »
I'm writting my codes like C++ in Object Pascal. Because I'm going to use object files (wrote with C++) from Object Pascal or Object Pascal codes from C++. So , I need to write OP codes compatible with C++.
What is your best opinion to initialize record types?
you don't need to initialize managed fields (like strings, interfaces, variants, dynamic arrays, etc.). Every managed field is implicitly initialized by nil/'' value.

The best way to initialize records (which was originally developed for NewPascal and was ported later to FPC) are management operators, see: http://wiki.freepascal.org/management_operators

This will be possible in next Delphi compiler version too  (Delphi 10.3 aka Carnival) but with different syntax:

Code: Pascal  [Select][+][-]
  1. TFoo = record
  2.   constructor Create;
  3.   destructor Destroy;
  4.   // + Copy operator in unknown form, AddRef operator is not mentioned anywhere, more details:
  5.   /// https://community.embarcadero.com/blogs/entry/august-2018-roadmap-commentary-from-product-management
  6. end;

management operators are really usefully for many further language extensions like support for nullable types  (but not only) which will be also introduced in Delphi 10.4 (or later) and also probably in NewPascal sooner (the management operators are base for both cases). The work is discontinued for FPC because I have ban and I am "persona non grata" in FPC core so you should not expect any improvements in this directions for FPC.
Checkout NewPascal initiative and donate beer - ready to use tuned FPC compiler + Lazarus for mORMot project

best regards,
Maciej Izak

engkin

  • Hero Member
  • *****
  • Posts: 3112
Re: How to use Write/WriteLn functions with record types?
« Reply #5 on: August 12, 2018, 10:00:37 pm »
The work is discontinued for FPC because I have ban and I am "persona non grata" in FPC core so you should not expect any improvements in this directions for FPC.
You can always submit patches if you want, can't you?

hnb

  • Sr. Member
  • ****
  • Posts: 270
Re: How to use Write/WriteLn functions with record types?
« Reply #6 on: August 12, 2018, 11:00:19 pm »
You can always submit patches if you want, can't you?
No. This was the scenario in the past and I was promoted to core developer. I have no motivation to start this path again. I was trying submitting patches again (for example some time ago with sending patches for my rtl-generics/Generics.Collections) but I felt really bad with this - rather no more again. I don't want to start new discussion why "I don't agree with motivations of ban". I just want to work on Open Source and don't be demotivated.
Checkout NewPascal initiative and donate beer - ready to use tuned FPC compiler + Lazarus for mORMot project

best regards,
Maciej Izak

avra

  • Hero Member
  • *****
  • Posts: 2514
    • Additional info
Re: How to use Write/WriteLn functions with record types?
« Reply #7 on: August 13, 2018, 11:36:25 am »
You can always submit patches if you want, can't you?
No.
I understand your point of view and I have great respect for your work, but you should be aware that such decision will shrink your user base a lot. I personally would not use NewPascal language features that will never get into FPC, and according to my understanding you will not even try to do that in the future. Unfortunately, for me that is a signal to significantly lower my interest in NewPascal, which is really sad.
 :(
ct2laz - Conversion between Lazarus and CodeTyphon
bithelpers - Bit manipulation for standard types
pasettimino - Siemens S7 PLC lib

ASerge

  • Hero Member
  • *****
  • Posts: 2242
Re: How to use Write/WriteLn functions with record types?
« Reply #8 on: August 13, 2018, 04:55:28 pm »
Code: Pascal  [Select][+][-]
  1. var
  2.   Obj : MyString;
  3. begin
  4.   Obj := MyString.Create('Hello World!');
  5.   // WriteLn(Obj.Data);   -----> This is working.
  6.   WriteLn(Obj); // This is not working, but I want this.
  7.   ReadLn;
  8. end.
  9.  
How can I do that? Thanks.
Write[ln] is not really a function, but rather a pseudo-function, and is compatible with earlier versions of the language. The compiler has a set of Write functions for some data types and substitutes them, depending on this. Or it says it's not familiar with this type. Create an explicit function with the desired parameter type, and use modern language mechanisms, such as implicit type conversion.
Code: Pascal  [Select][+][-]
  1. {$APPTYPE CONSOLE}
  2. {$MODE OBJFPC}
  3. {$MODESWITCH ADVANCEDRECORDS}
  4.  
  5. type
  6.   TMyString = record
  7.   private
  8.     FData: UnicodeString;
  9.   public
  10.     property Data: UnicodeString read FData write FData;
  11.     procedure Init(const AData: UnicodeString = '');
  12.     class operator := (const AMyString: TMyString): UnicodeString;
  13.   end;
  14.  
  15. class operator TMyString. := (const AMyString: TMyString): UnicodeString;
  16. begin
  17.   Result := AMyString.FData;
  18. end;
  19.  
  20. procedure TMyString.Init(const AData: UnicodeString);
  21. begin
  22.   FData := AData;
  23. end;
  24.  
  25. procedure WritelnStr(const S: UnicodeString); inline;
  26. begin
  27.   Writeln(S);
  28. end;
  29.  
  30. var
  31.   R: TMyString;
  32. begin
  33.   R.Init('Hello World!');
  34.   WritelnStr(R);
  35.   Readln;
  36. end.

440bx

  • Hero Member
  • *****
  • Posts: 4037
Re: How to use Write/WriteLn functions with record types?
« Reply #9 on: August 13, 2018, 05:34:39 pm »
Code: Pascal  [Select][+][-]
  1. var
  2.   Obj : MyString;
  3. begin
  4.   Obj := MyString.Create('Hello World!');
  5.   // WriteLn(Obj.Data);   -----> This is working.
  6.   WriteLn(Obj); // This is not working, but I want this.
  7.   ReadLn;
  8. end.
  9.  
How can I do that? Thanks.

I wanted to offer a variation of what Serge above offered.  You can simply overload the writeln function to output your object/class however you like.  What follows is a very simple example that shows how to use writeln with a type it cannot display.  It could easily be changed to display Obj.data whenever the compiler finds writeln(Obj).

Code: Pascal  [Select][+][-]
  1. program writelnoverload;
  2.  
  3. const
  4.   // writeln doesn't output widechars
  5.  
  6.   awidestring : pwidechar = 'a widecharacter string';
  7.  
  8. // overload writeln
  9.  
  10. procedure writeln(param : pwidechar); inline;
  11. begin
  12.   system.writeln(unicodestring(param));
  13. end;
  14.  
  15. begin
  16.   // use the overload
  17.  
  18.   writeln(awidestring);
  19. end.
  20.  

Basically, write little wrappers that implement C++ features you need.

HTH.
(FPC v3.0.4 and Lazarus 1.8.2) or (FPC v3.2.2 and Lazarus v3.2) on Windows 7 SP1 64bit.

mjollnir357

  • Newbie
  • Posts: 1
Re: How to use Write/WriteLn functions with record types?
« Reply #10 on: August 15, 2018, 05:02:06 pm »
First cut, overload the Write/WriteLn procedures. A bit awkward, as it needs to be done for each new type, and full qualification is needed to get the original Write/WriteLn.

Code: Pascal  [Select][+][-]
  1. // author: Mark W. Naylor
  2. // file:  recordwrite.pas
  3. // date:  2018-Aug-12
  4.  
  5.  
  6. program RecordWrite;
  7.  
  8. type
  9.  
  10.    TPerson = record
  11.       FirstName: String;
  12.       LastName: String;
  13.    end;
  14.  
  15.    procedure Write(Person: TPerson); overload;
  16.    begin
  17.      System.Write('My name is ' + Person.FirstName + ' ' + Person.LastName + '.');
  18.    end; {Write}
  19.  
  20.    procedure WriteLn(Person: TPerson); overload;
  21.    begin
  22.       Write(Person);
  23.       System.WriteLn;
  24.    end; {WriteLn}
  25.  
  26. var
  27.    SpaceHero: TPerson;
  28.  
  29. begin
  30.    with SpaceHero do
  31.    begin
  32.       FirstName := 'Flash';
  33.       LastName := 'Gordon';
  34.    end; { with SpaceHero }
  35.  
  36.    WriteLn(SpaceHero);
  37.  
  38. end. { RecordWrite }
  39.  

What we really want to do is overload just once, but records aren't classes.
Code: Pascal  [Select][+][-]
  1. // author: Mark W. Naylor
  2. // file:  recordwrite.pas
  3. // date:  2018-Aug-12
  4.  
  5.  
  6. program RecordWrite;
  7.  
  8. type
  9.  
  10.    TPerson = record
  11.       FirstName: String;
  12.       LastName: String;
  13.  
  14.       function ToString(): String;
  15.    end;
  16.  
  17.    function TPerson.ToString(): String;
  18.    begin
  19.       Result := 'My name is ' + FirstName + ' ' + LastName + '.';
  20.    end; {TPerson.ToSting}
  21.  
  22.  
  23.    // What we really want to do is overload Write and WriteLn just once.
  24.    procedure Write(Obj: TObject); overload;
  25.    begin
  26.      System.Write(Obj.ToString());
  27.    end; {Write}
  28.  
  29.    procedure WriteLn(Obj: TObject); overload;
  30.    begin
  31.       Write(Obj);
  32.       System.WriteLn;
  33.    end; {WriteLn}
  34.  
  35.  
  36.  
  37. var
  38.    SpaceHero: TPerson;
  39.  
  40. begin
  41.    with SpaceHero do
  42.    begin
  43.       FirstName := 'Flash';
  44.       LastName := 'Gordon';
  45.    end; { with SpaceHero }
  46.  
  47.    // Next line will cause compiler error. Unfortunately, records are not objects.
  48.    // WriteLn(SpaceHero);
  49.  
  50.    (*
  51.    Full qualification needed to call original WriteLn. And, we need to directly call the ToString method.
  52.    *)
  53.  
  54.    System.WriteLn(SpaceHero.ToString());
  55.  
  56. end. { RecordWrite }
  57.  
  58.  


Since the record already has methods, why not make it an actual class?
Code: Pascal  [Select][+][-]
  1. // author: Mark W. Naylor
  2. // file:  recordwrite.pas
  3. // date:  2018-Aug-12
  4.  
  5. program RecordWrite;
  6.  
  7. uses
  8.    SysUtils;
  9.  
  10. type
  11.  
  12.    // Better yet, maybe, upgrade from record to actual class.
  13.    TPerson = class
  14.       fFirstName: String;
  15.       fLastName: String;
  16.  
  17.       function ToString(): String; override;
  18.       constructor Create(FirstName: String; LastName: String);
  19.    end;
  20.  
  21.    function TPerson.ToString(): String;
  22.    begin
  23.       Result := 'My name is ' + fFirstName + ' ' + fLastName + '.';
  24.    end; {TPerson.ToSting}
  25.  
  26.    constructor TPerson.Create(FirstName: String; LastName: String);
  27.    begin
  28.       fFirstName := FirstName;
  29.       fLastName := LastName;
  30.    end; {TPerson.Create}
  31.  
  32.    // What we really want to do is overload Write and WriteLn just once.
  33.    procedure Write(Obj: TObject); overload;
  34.    begin
  35.       System.Write(Obj.ToString());
  36.    end; {Write}
  37.  
  38.    procedure WriteLn(Obj: TObject); overload;
  39.    begin
  40.       Write(Obj);
  41.       System.WriteLn;
  42.    end; {WriteLn}
  43.  
  44. var
  45.    SpaceHero: TPerson;
  46.  
  47. begin
  48.  
  49.    SpaceHero := TPerson.Create('Flash', 'Gordon');
  50.  
  51.    WriteLn(SpaceHero);
  52.  
  53.    FreeAndNil(SpaceHero);
  54.  
  55. end. { RecordWrite }
  56.  
  57.  


This allows us to do specialized output.

Code: Pascal  [Select][+][-]
  1. // author: Mark W. Naylor
  2. // file:  recordwrite.pas
  3. // date:  2018-Aug-12
  4.  
  5. program RecordWrite;
  6.  
  7. uses
  8.    SysUtils;
  9.  
  10. type
  11.  
  12.    // Better yet, maybe, upgrade from record to actual class.
  13.    TPerson = class
  14.    public
  15.       function ToString(): String; override;
  16.       constructor Create(FirstName: String; LastName: String);
  17.    private
  18.       fFirstName: String;
  19.       fLastName: String;
  20.    end;
  21.  
  22.    // Heros are more than ordinary people. ////////////////////////////////////
  23.    THero = class(TPerson)
  24.    public
  25.       constructor Create(FirstName: String; LastName: String; TagLine: String);
  26.       constructor Create(FirstName: String; LastName: String);
  27.       function ToString(): String; override;
  28.    private
  29.       fTagLine: String;
  30.  
  31.    end; { THero }
  32.  
  33.    // TPerson implementation //////////////////////////////////////////////////
  34.    function TPerson.ToString(): String;
  35.    begin
  36.       Result := 'My name is ' + fFirstName + ' ' + fLastName + '.';
  37.    end; {TPerson.ToSting}
  38.  
  39.    constructor TPerson.Create(FirstName: String; LastName: String);
  40.    begin
  41.       fFirstName := FirstName;
  42.       fLastName := LastName;
  43.    end; {TPerson.Create}
  44.  
  45.    // THero implementation ////////////////////////////////////////////////////
  46.    constructor THero.Create(FirstName: String; LastName: String);
  47.    begin
  48.       inherited Create(FirstName, LastName);
  49.    end; {THero.Create}
  50.  
  51.  
  52.    constructor THero.Create(FirstName: String; LastName: String; TagLine: String);
  53.    begin
  54.       inherited Create(FirstName, LastName);
  55.       fTagLine := TagLine;
  56.    end; {THero.Create}
  57.  
  58.    function THero.ToString() : String;
  59.    begin
  60.       Result := inherited ToString() + ' I''m a hero.' + Chr(10) + fTagLine;
  61.    end; {THero.ToString}
  62.  
  63.  
  64.    // What we really want to do is overload Write and WriteLn just once.
  65.    procedure Write(Obj: TObject); overload;
  66.    begin
  67.       System.Write(Obj.ToString());
  68.    end; {Write}
  69.  
  70.    procedure WriteLn(Obj: TObject); overload;
  71.    begin
  72.       Write(Obj);
  73.       System.WriteLn;
  74.    end; {WriteLn}
  75.  
  76. var
  77.    OrdinaryPerson: TPerson;
  78.    SpaceHero: TPerson;
  79.    GreenLantern: TPerson;
  80.  
  81. begin
  82.  
  83.    SpaceHero := THero.Create('Flash', 'Gordon',
  84.                              'Flash a-ah' + Chr(10) +
  85.                              'Savior of the Universe' + Chr(10) +
  86.                              'Flash a-ah' + Chr(10) + 'He''ll save every one of us');
  87.    OrdinaryPerson := TPerson.Create('John', 'Doe');
  88.  
  89.    GreenLantern := THero.Create('Hal', 'Jordan');
  90.  
  91.  
  92.    WriteLn(OrdinaryPerson);
  93.    System.WriteLn();
  94.  
  95.    WriteLn(SpaceHero);
  96.    System.WriteLn();
  97.  
  98.    WriteLn(GreenLantern);
  99.  
  100.    FreeAndNil(OrdinaryPerson);
  101.    FreeAndNil(SpaceHero);
  102.    FreeAndNil(GreenLantern);
  103.  
  104. end. { RecordWrite }
  105.  
  106.  

Note: all code compiled in delphi mode.

 

TinyPortal © 2005-2018