Recent

Author Topic: Function / procedure templates ?  (Read 6042 times)

Nitorami

  • Hero Member
  • *****
  • Posts: 605
Function / procedure templates ?
« on: April 12, 2015, 10:08:41 am »
Hi all

Is there anything like templates for method declarations ?

When overriding virtual methods in ancestor Classes, the method needs to be redeclared each time. Whenever I modify the method declaration, I have to do this for all Classes individually. I tried to do it via procedure type but it does not work this way round:

Code: [Select]
type TStateProc = procedure (const a: bool; const b: TInputID) of object;
procedure GetState: TProcessStateProc; //that does not work

Not sure why but I guess it is reasonable to disallow this construct because the parameter names a and b are only spareholders.
A macro does the job but only in the interface part and not the implementation, and I find it kludgy... any alternatives ?

argb32

  • Jr. Member
  • **
  • Posts: 89
    • Pascal IDE based on IntelliJ platform
Re: Function / procedure templates ?
« Reply #1 on: April 12, 2015, 11:15:16 am »
Changes to a method signature is a refactoring. Therefore it should be handled by IDE.

Nitorami

  • Hero Member
  • *****
  • Posts: 605
Re: Function / procedure templates ?
« Reply #2 on: April 12, 2015, 11:23:11 am »
I fear I do not quite understand what you try to tell me...

Blaazen

  • Hero Member
  • *****
  • Posts: 3241
  • POKE 54296,15
    • Eye-Candy Controls
Re: Function / procedure templates ?
« Reply #3 on: April 12, 2015, 11:36:19 am »
If you change
Code: [Select]
type TStateProc = procedure (const a: bool; const b: TInputID) of object;to
Code: [Select]
type TStateProc = procedure (const a: bool; const b: TInputID; c: char) of object;you can hit CTRL+SHIFT+C and it should "repair" the implementation.

However, this
Code: [Select]
procedure GetState: TProcessStateProc;would be a nice feature.
Lazarus 2.3.0 (rev main-2_3-2863...) FPC 3.3.1 x86_64-linux-qt Chakra, Qt 4.8.7/5.13.2, Plasma 5.17.3
Lazarus 1.8.2 r57369 FPC 3.0.4 i386-win32-win32/win64 Wine 3.21

Try Eye-Candy Controls: https://sourceforge.net/projects/eccontrols/files/

Basile B.

  • Guest
Re: Function / procedure templates ?
« Reply #4 on: April 12, 2015, 12:09:24 pm »
Hi all

Is there anything like templates for method declarations ?

When overriding virtual methods in ancestor Classes, the method needs to be redeclared each time. Whenever I modify the method declaration, I have to do this for all Classes individually. I tried to do it via procedure type but it does not work this way round:

Code: [Select]
type TStateProc = procedure (const a: bool; const b: TInputID) of object;
procedure GetState: TProcessStateProc; //that does not work

Not sure why but I guess it is reasonable to disallow this construct because the parameter names a and b are only spareholders.
A macro does the job but only in the interface part and not the implementation, and I find it kludgy... any alternatives ?

Pascal would need something like type tuples (type list) to do this and or variadic parameter. In this case i would imagine:

Code: [Select]
type
  TMyTupleDefinition = tuple(char, integer, string); // anonymous style
  TMyTupleDefinition2 = tuple(a: char, b: integer, c:  string); // named style

  TFoo = class
      procedure proc(params: TMyTupleDefinition); virtual;
      procedure proc2(params: TMyTupleDefinition2); virtual;
  end;

with tuple(): a compiler magic function which would allow to create parameters "pack". More or less some kinds of POD record.

In the implementation, a usage would be

Code: [Select]
TFoo.proc(params: TMyTupleDefinition);
var
  i: integer;
begin
  for i:= 0 to high(params) do
    writeln(params[i]);
  //
end;

Code: [Select]
procedure  TFoo.proc2(params: TMyTupleDefinition2);
var
  i: integer;
begin
  writeln(params.a);
  writeln(params.b);
end;

The fact is that the problem you mention is often solved using a struct/record instead of parameters.
When you update the record which contains the parameters you don't need to update each overriden method.

Code: [Select]
  TMyParameters = record
  end;

  TFoo = class
      procedure proc(params: TMyParameters ); virtual;
  end;

The only problem is that a function call might be a bit less efficient, according to the ABI and the call convention.
« Last Edit: April 12, 2015, 12:18:51 pm by Basile B. »

Nitorami

  • Hero Member
  • *****
  • Posts: 605
Re: Function / procedure templates ?
« Reply #5 on: April 12, 2015, 12:41:58 pm »
Passing a record would be a simple and viable option, but we would have to organise the Class fields accordingly because afaik it is not possible to construct a record from individual elements on the fly. In a construct like

Code: [Select]
TMyRecord = record
                         a: boolean;
                         b: integer;
                     end;
 
TMyClass = Class
                     a1,a2: boolean;
                     foo: string;
                     b1,b2: integer; 
                     procedure GetState (const Rec: TMyRecord);
                   end;

we could try something like this
Code: [Select]
MyClass.GetState (TMyRecord (a1,b2));
but this does not work. I don't know whether it would be reasonably feasible for a compiler in the first place. It just looks tempting.

Basile B.

  • Guest
Re: Function / procedure templates ?
« Reply #6 on: April 12, 2015, 01:17:04 pm »
Yes, you're right.
This would be great to have a default constructor for record. For example unless a constructor is defined, a default would exist which would take each field as parameters.

Some other languages have this feature and it's very handy. For example in D you can do that.

As you've noted this is the only thing needed to use the "record or parameters" pattern. I don't know if is it worth proposing this to the FPC team ?
« Last Edit: April 12, 2015, 01:19:44 pm by Basile B. »

howardpc

  • Hero Member
  • *****
  • Posts: 4144
Re: Function / procedure templates ?
« Reply #7 on: April 12, 2015, 02:51:54 pm »
You can do something along those lines already using advanced records and default constructor parameters.

Code: [Select]
program Project1;

{$mode objfpc}{$H+}
{$ModeSwitch advancedrecords}

type

{ TMyRecord }

  TMyRecord = record
    a, b, c: integer;
    procedure Init(anA: integer=0; aB: integer=1; aC: integer=2);
  end;

{ TMyClass }

  TMyClass = Class
  strict private
    FRec: TMyRecord;
  public
    function GetState: TMyRecord;
    constructor Create;
    constructor Create(const aRec: TMyRecord);
  end;

{ TMyClass }

constructor TMyClass.Create;
begin
  inherited Create;
  FRec.Init();
end;

function TMyClass.GetState: TMyRecord;
begin
  Result:=FRec;
end;

constructor TMyClass.Create(const aRec: TMyRecord);
begin
  inherited Create;
  FRec:=aRec;
end;

{ TMyRecord }

procedure TMyRecord.Init(anA: integer; aB: integer; aC: integer);
begin
  a:=anA;
  b:=aB;
  c:=aC;
end;

var
  mc: TMyClass;
  mr: TMyRecord;

begin
  WriteLn('Default constructor:');
  mc:=TMyClass.Create;
  mr:=mc.GetState;
  WriteLn('TMyClass record values are a=',mr.a,' b=',mr.b,' c=',mr.c);
  mc.Free;
  WriteLn;
  mr.Init(100,200,300);
  WriteLn('With overloaded constructor:');
  mc:=TMyClass.Create(mr);
  mr:=mc.GetState;
  WriteLn('TMyClass record values are a=',mr.a,' b=',mr.b,' c=',mr.c);
  mc.Free;
  ReadLn;
end.


Nitorami

  • Hero Member
  • *****
  • Posts: 605
Re: Function / procedure templates ?
« Reply #8 on: April 12, 2015, 04:46:34 pm »
In fact, and I find default parameters very convenient. The code does not even need the advanced records switch if we make TMyRecord an object instead of a record:

Code: [Select]
TMyRecord = object....

But the idea was slightly different, constructing dynamic records at the moment when passing them to a procedure, similar as is possible for dynamic arrays

Code: [Select]
procedure Foo (s: array of string);
begin
end;

begin
  Foo (['This', 'is', 'great']);
end.

 

TinyPortal © 2005-2018