Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / fpc-pascal / 2009-11

Generic type declaration example versus manual.

20 messages · 8 people · –

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

Pascal

Hello.

In example tgeneric16.pp (from FPC 2.2.4 sources) the generic type
TStack is declared as:
type
   { TStack }
   generic TStack<T> = class(TObject)
    public
     procedure Clear; virtual;
     destructor Destroy; override;
   end;

Though in FPC manual type is described as:
type declaration: identifier = type ;
type: simple type
string type
structured type
pointer type
procedural type
generic type
specialized type
type identifier
generic type: generic identifier < template list > = generic class ;

Following the manual, the type identifier is thus declared two times:
- in type declaration
- in generic type
Like:
TStack = generic TStack<T> = class(TObject)

    public
     procedure Clear; virtual;
     destructor Destroy; override;
   end;

The syntax found in the example doesn't take care of the first identifier in type declaration.

May I suggest the following:
   TStack = generic <T> class(TObject)
    public
     procedure Clear; virtual;
     destructor Destroy; override;
   end;

This syntax looks like more Pascal conformant, i.e. it doesn't brake Pascal type declaration "identifier = type;"
And this prevent the succession of greater and equal characters in "generic TStack<T>=class(TObject)" which may be considered as greater or equal ">=" by the compiler.

For sure, the simpler would be to change the manual ;-)

What are your feedbacks ?

Regards, Pascal.
http://blady.pagesperso-orange.fr

Reply by email

Jonas Maebe
to Pascal
Pascal wrote
In example tgeneric16.pp (from FPC 2.2.4 sources) the generic type TStack is declared as:

tgeneric16.pp is not an example, it's a test. Moreover, it doesn't compile yet, not even with FPC 2.5.1. So documenting that syntax is not really a good idea.

Jonas

Reply by email

Micha Nelissen
to Jonas Maebe
Jonas Maebe wrote
tgeneric16.pp is not an example, it's a test. Moreover, it doesn't compile yet, not even with FPC 2.5.1. So documenting that syntax is not really a good idea.

His comment doesn't really apply to tgeneric16 specifically, but more to generic syntax in general.

Micha

Reply by email

Anthony Walter
to Micha Nelissen

I haven't used generics in FPC, but really have to ask, is they keyword generic really necessary? Shouldn't generics be declared like this:

type
  TList<T> = class
  private
     ...
  public
    function Add: T;
    procedure Remove(Item: T);
    property Item[Index: Integer]: T read Get write Put; default;
  end;

I believe this makes the most sense, and it's also how they are declared in Delphi.

It would be a real shame to create more Delphi incompatibilities.

Micha Nelissen wrote 14 lines
Jonas Maebe wrote: > > tgeneric16.pp is not an example, it's a test. Moreover, it doesn't compile > yet, not even with FPC 2.5.1. So documenting that syntax is not really a > good idea. His comment doesn't really apply to tgeneric16 specifically, but more to  generic syntax in general. Micha _______________________________________________ fpc-pascal maillist  -   http://lists.freepascal.org/mailman/listinfo/fpc-pascal

Reply by email

Jonas Maebe
to Anthony Walter
Anthony Walter wrote
It would be a real shame to create more Delphi incompatibilities.

Generics were developed in parallel in FPC and in Delphi, and both came up with a different syntax. The incompatibility was there from the start, it wasn't created afterwards.

Jonas

Reply by email

Anthony Walter
to Jonas Maebe
Jonas Maebe wrote
Generics were developed in parallel in FPC and in Delphi, and both came up with a different syntax. The incompatibility was there from the start, it wasn't created afterwards.

Jonas,

I am not trying to be a jerk or anything, but yes, I assure you I read your replies. I say this because you are repeating the same logic as if I hadn't heard it before.

For your benefit I'll include my a quote myself from last time we went down this path.

Hopefully we can move past the "who did what when" discussion, and take up "what makes more sense, and should we try to be compatible" discussion.

Quoting myself from a recent discussion:

One thing I've noticed about the FPC community which has me a somewhat apprehensive is a bit of a particular attitude I've picked up on.

A few times now I've read comments by or had conversations with people in the FPC community who have explained incompatibilities away using the phrase:

"FreePascal did this before something else so we shouldn't change"

Forgetting the whole argument about who was actually first, I have to ask what difference does it make?

Why does doing something first make it written in stone. It seems a bit childish to say, "No way, I way here first, I won't budge. You move."

Really, that attitude is quite the turn off.

There there these incompatibilities causing me to avoid language features. I'd like to use them but just won't (Operator overloading and generics come to mind), mostly because I really don't want to have ifdefs all over the place.

In my opinion, there is an incompatibility. Fix it.

Reply by email

Marco van de Voort
to Anthony Walter

In our previous episode, Anthony Walter said:

Show quoted text 6 lines
> Generics were developed in parallel in FPC and in Delphi, and both came up with a different syntax. > The incompatibility was there from the start, it wasn't created afterwards. I am not trying to be a jerk or anything, but yes, I assure you I read your replies. I say this because you are repeating the same logic as if I hadn't heard it before.

Apparantly it didn't sink in:-)

Show quoted text 6 lines
For your benefit I'll include my a quote myself from last time we went down this path. Hopefully we can move past the "who did what when" discussion, and take up "what makes more sense, and should we try to be compatible" discussion.

I think that is a past station. I would move directly to the "who is going to do it" discussion.

Forgetting the whole argument about who was actually first, I have to ask what difference does it make?

Implementing something once or twice.

Why does doing something first make it written in stone. It seems a bit childish to say, "No way, I way here first, I won't budge. You move."

Every developer is master of his own time. And it is an hobby for all of us. And I don't think i have to explain you that implementing something twice is not fun, specially not if your only motivation is avoiding being called "childish".

From past experience, in such cases usually at some point (possibly

considerably later) somebody implements it, typically somebody else, often a newer developer.

Unfortunately, generics is a quite big feature, much bigger than past ones.

You can rush this by being that implementing developer, or try to motivate one (e.g. with bounties or employment)

And of course make sure Codegear knows your pain, so that this can be avoided in the future, by making clear that compatibility and avoiding breakage with FPC is worth something to their customers.

It might not work directly, but if they hear it often enough, they might get more cooperative over time, and communication channels might develop.

Reply by email

Anthony Walter
to Marco van de Voort
Marco van de Voort wrote
Apparantly it didn't sink in:-)

Oh it has sunk in, and I've come to expect it. I was/am only trying to move the discussion beyond that point (which seems like a brick wall). IMO a discussion would serve us better than stonewalling.

Implementing something once or twice.

Okay, but let's take these issues one by one rather than grouping them together. Is that more reasonable. Blocking off discussion about some feature after it has been started or implemented seems short sighted. Sure, you resolve the issue, but it's done by shutting down opinions.

To address this issue directly (which is what I'd prefer to do), is it really that much trouble to convert the syntax from:

A) generic TStack<T> = class(TObject)
versus
B) TStack<T> = class(TObject)

Points:

The work that has been done I am guessing is mostly in the generation of code templates, rather than the syntax parsing.

Version A repeats redundant information. Of couse TStack<T> is generic, it has those angle brackets after the identifier. They wouldn't be legal in a type block unless it was a generic declaration. Therefore the word generic is redundant.

As I've said before, FPC is going down the route of being incompatible with Delphi. I think it makes sense to resolve compatibility issues rather than fight against resolving them.

Every developer is master of his own time. And it is an hobby for all of us. And I don't think i have to explain you that implementing something twice is not fun, specially not if your only motivation is avoiding being called "childish".

I didn't call anyone childish. I was pointing out that some arguments are childish. I've taught in elementary school and have had the same problems with students. "Teacher: Stop acting stupid. Student: Hey, that's unfair, you just called me stupid. Teacher: No, I said you were acting stupid"

Reply by email

Marco van de Voort
to Anthony Walter
Show quoted text 7 lines
On Sun, Nov 22, 2009 at 10:27 AM, Marco van de Voort wrote: > Implementing something once or twice. Okay, but let's take these issues one by one rather than grouping them together. Is that more reasonable. Blocking off discussion about some feature after it has been started or implemented seems short sighted.

It is not blocked off. I'm absolutely sure that a patch which implements Delphi compatible generics will be accepted.

As I've said before, FPC is going down the route of being incompatible with Delphi. I think it makes sense to resolve compatibility issues rather than fight against resolving them.

By all means, go ahead.

Show quoted text 7 lines
> Every developer is master of his own time. And it is an hobby for all of us. > And I don't think i have to explain you that implementing something twice is > not fun, specially not if your only motivation is avoiding being called > "childish". I didn't call anyone childish. I was pointing out that some arguments are childish.

You seem to bypass the main argument time after time again: who is going to pay for Codegear's non compliance?

You seem to assume the FPC devels will, and morally should, pick up that bill. (which can be expressed as developer time), and with the highest priority.

Which is simply false.

To my best knowledge all FPC compatibility statements (intention or not) never went further than Delphi 7 compability plus maybe selected features from later versions. Everything else is an assumption.

Reply by email

Michael Van Canneyt
to Anthony Walter: Oh it has sunk in, and I've come to expect it. I was/am only trying to move the…
Anthony Walter wrote 31 lines
On Sun, Nov 22, 2009 at 10:27 AM, Marco van de Voort wrote: > > Apparantly it didn't sink in:-) Oh it has sunk in, and I've come to expect it. I was/am only trying to move the discussion beyond that point (which seems like a brick wall). IMO a discussion would serve us better than stonewalling. > Implementing something once or twice. Okay, but let's take these issues one by one rather than grouping them together. Is that more reasonable. Blocking off discussion about some feature after it has been started or implemented seems short sighted. Sure, you resolve the issue, but it's done by shutting down opinions. To address this issue directly (which is what I'd prefer to do), is it really that much trouble to convert the syntax from: A) generic TStack<T> = class(TObject) versus B) TStack<T> = class(TObject) Points: The work that has been done I am guessing is mostly in the generation of code templates, rather than the syntax parsing. Version A repeats redundant information. Of couse TStack<T> is generic, it has those angle brackets after the identifier. They wouldn't be legal in a type block unless it was a generic declaration. Therefore the word generic is redundant.

Well, in

Var
   A : Integer;

The 'Var' is strictly speaking also redundant, as the : is used only in variable declarations. But the 'var' makes it easier to read, and Pascal is a verbose language. Additionally, the parsing is easier to do, as you know what to expect next. By that rationale, the 'generic' keyword was deemed appropriate when FPC made it's implementation.

We'll resolve the incompatibility - remaining backwards compatible to FPC itself - when someone finds the time and desire to do so.

Or when someone from our beloved users sends us a patch to this effect.

Michael.

Reply by email

Marco van de Voort
to Michael Van Canneyt

In our previous episode, Michael Van Canneyt said:

Show quoted text 15 lines
> Version A repeats redundant information. Of couse TStack<T> is > generic, it has those angle brackets after the identifier. They > wouldn't be legal in a type block unless it was a generic declaration. > Therefore the word generic is redundant. Well, in Var A : Integer; The 'Var' is strictly speaking also redundant, as the : is used only in variable declarations. But the 'var' makes it easier to read, and Pascal is a verbose language. Additionally, the parsing is easier to do, as you know what to expect next. By that rationale, the 'generic' keyword was deemed appropriate when FPC made it's implementation.

(Redundancy plays its main role in case of detecting errors and error-recovery. Both in natural as artificial languages. Errormessage quality is one of the main benefits of FPC/Delphi IMHO )

Reply by email

Jonas Maebe
to Anthony Walter: I am not trying to be a jerk or anything, but yes, I assure you I read your replies. I…
Anthony Walter wrote 8 lines
n Sun, Nov 22, 2009 at 6:15 AM, Jonas Maebe wrote: > > Generics were developed in parallel in FPC and in Delphi, and both came up with a different syntax. > The incompatibility was there from the start, it wasn't created afterwards. I am not trying to be a jerk or anything, but yes, I assure you I read your replies. I say this because you are repeating the same logic as if I hadn't heard it before.

No, I was replying to specifically this statement of yours:

It would be a real shame to create more Delphi incompatibilities.

I agree with you that creating more Delphi compatibilities is generally bad, but I was trying to explain that in fact nobody is creating more Delphi incompatibilities here (unlike what the above suggests). It is just as frustrating for me to read statements like the above that wrongly suggest that someone is working on implementing a feature in a Delphi-incompatible way, as it is to you to read the explanation that it is not our fault that things already are incompatible (and in this case: not Borland/CodeGear/Embarcadero's fault either).

Jonas

Reply by email

Pascal

Hello Anthony.

Thanks for your proposal.
I'm a bit surprised of Delphi chosen syntax because "TList<T>=class ..." breaks Pascal usual type declaration "Id=type;" and "<T>=" may be confused with greater or equal operator.

Have you some documentation available on Internet? The one I found is Delphi Object Pascal Language Guide, version 7, 2002. http://docs.codegear.com/products/rad_studio/delphi7/ D7_DevelopersGuide.pdf
Generic types are not described in it ;-(

Best, Pascal.
http://blady.pagesperso-orange.fr

Show quoted text 22 lines
From: Anthony Walter Subject: Re: [fpc-pascal] Generic type declaration example versus manual. I haven't used generics in FPC, but really have to ask, is they keyword generic really necessary? Shouldn't generics be declared like this: type TList<T> = class private ... public function Add: T; procedure Remove(Item: T); property Item[Index: Integer]: T read Get write Put; default; end; I believe this makes the most sense, and it's also how they are declared in Delphi. It would be a real shame to create more Delphi incompatibilities.

Reply by email

Anthony Walter
to Michael Van Canneyt: Well, in Var A : Integer; The 'Var' is strictly speaking also redundant, as the : is used…
Michael Van Canneyt wrote 15 lines
Well, in Var  A : Integer; The 'Var' is strictly speaking also redundant, as the : is used only in variable declarations. But the 'var' makes it easier to read, and Pascal is a verbose language. Additionally, the parsing is easier to do, as you know what to expect next. By that rationale, the 'generic' keyword was deemed appropriate when FPC made it's implementation. We'll resolve the incompatibility - remaining backwards compatible to FPC itself - when someone finds the time and desire to do so. Or when someone from our beloved users sends us a patch to this effect.

Michael,

Actually, you are pretty far off. I've written a few parsers for Delphi and before generics it has ALWAYS gone like this:

// comments are considered transparent

After: {unit|program|library} ident ; [interface] [uses section]

Next must be either: {block|function/procedure|section}

A block always starts with one the following keywords: {var|const|type|resourcestring}

A section can be one of the followings:
[implementation|initialization|finalization]

When block is detected {var|threadvar|const|resourcestring|type} it always goes like this:

block

  ident {:|=} body [end];
  {repeat above flow|{block|function/procedure|section}}

A block example:

const
  // okay, starting a new block {const}
  // next parsed token must be an ident
  // repeat *NEXT TOKEN MUST BE* an ident
  WM_SOMETHING
  // okay, got ident
  // in {const} block next token must now be =
  =
  // next tokens must a constant expression
  WM_USER + $FF
  // okay we read a constant express
  ;
  // okay, terminated
  // now expecting {ident|[block|function/procedure|section]}
  WM_OTHERTHING = WM_SOMETHING + 1;
  WM_LASTTHING = OTHERTHING + 1;
var
  // okay, starting a new block {var}
  // next parsed token must be an ident
...

So this has always been the case. When the parser encounters {var|const|type|resourcestring} in the context of creating a new block, the next token is always, ALWAYS an identifier.

type
  // okay, starting new block {type}
  // next token must be an identifier
  TTime
  // okay, got ident
  // in {type} block next token must now be =
 =
  // next token must be one of the following
  // {ident|array|class|record|set|(|type}
  Double
  // read ident, verify value refers to an already typed ident
  // next token must be ;
  ;
  // okay, terminated
  // now expecting {ident|{block|function/procedure|section}}
  TPoint = record X: Integer; Y: Integer; end;

Go it? So whenever you have {var|threadvar|const|type|resourcestring} in the context of creating a block, the next token will always be an ident, or the code is invalid.

You've always had the case where

program A;
type
// the next thing read must be an ident

That's how it's always been. Delphi has always been about {block|function/procedure|section}.

Block has ALWAYS been like this:

block

  ident {:|=} body [end];
  {repeat above flow|{block|function/procedure|section}}

Putting the word "generic" infront of the ident breaks the long established trend.

type generic TList<T> = class end;

See, we started a block {type} and introduced a keyword {generic} before the identifier {TList}. This unnecessarily breaks the pattern and is inconsistent.

Reply by email

Anthony Walter
to Jonas Maebe: http://docs.embarcadero.com/products/rad_studio/delphiAndcpp2009/HelpUpdate2/EN/pdf/devcom…

As a follow up, here are a few generic type declaration examples lifted directly out of the CodeGear pdf Jonas was thoughtful enough to link:

*Please Note* These examples do not include generic constraints which I believe are needed to work effectively with generics. Generic constraints can be found in the referenced pdf section "3.1.3.3.5 Constraints in Generics" page 626

type
 TFoo1<T> = class(TBar) // Actual type
 end;
 TFoo2<T> = class(TBar2<T>) // Open constructed type
 end;
 TFoo3<T> = class(TBar3<Integer>) // Closed constructed type
 end;
 TMyProc<T> = procedure(Param: T); // procedure type
 TMyProc2<Y> = procedure(Param1, Param2: Y) of object;  // event type
 TRecord<T> = record
   FData: T;
 end;
 IAncestor<T> = interface
   function GetRecord: TRecord<T>;
 end;
 IFoo<T> = interface(IAncestor<T>)
   procedure AMethod(Param: T);
 end;
 TFoo<T> = class(TObject, IFoo<T>)
   FField: TRecord<T>;
   procedure AMethod(Param: T);
   function GetRecord: TRecord<T>;
 end;

Reply by email

Anthony Walter
to Jonas Maebe: http://docs.embarcadero.com/products/rad_studio/delphiAndcpp2009/HelpUpdate2/EN/pdf/devcom…

I improperly replied. Let me try that again.....

As a follow up, here are a few generic type declaration examples lifted directly out of the CodeGear pdf Jonas was thoughtful enough to link:

*Please Note* These examples do not include generic constraints which I believe are needed to work effectively with generics. Generic constraints can be found in the referenced pdf section "3.1.3.3.5 Constraints in Generics" page 626

type
 TFoo1<T> = class(TBar) // Actual type
 end;
 TFoo2<T> = class(TBar2<T>) // Open constructed type
 end;
 TFoo3<T> = class(TBar3<Integer>) // Closed constructed type
 end;
 TMyProc<T> = procedure(Param: T); // procedure type
 TMyProc2<Y> = procedure(Param1, Param2: Y) of object;  // event type
 TRecord<T> = record
  FData: T;
 end;
 IAncestor<T> = interface
  function GetRecord: TRecord<T>;
 end;
 IFoo<T> = interface(IAncestor<T>)
  procedure AMethod(Param: T);
 end;
 TFoo<T> = class(TObject, IFoo<T>)
  FField: TRecord<T>;
  procedure AMethod(Param: T);
  function GetRecord: TRecord<T>;
 end;

Reply by email

Graeme Geldenhuys
to Anthony Walter: I am not trying to be a jerk or anything, but yes, I assure you I read your replies. I…
Anthony Walter wrote
"FreePascal did this before something else so we shouldn't change" Forgetting the whole argument about who was actually first, I have to ask what difference does it make?

I'm not a FPC developer, just a FPC user. But even I can see the logic behind there choice.

FPC implemented a lot of things before Delphi. So first off, why must FPC wait until Borland (and the time) and now Embarcadero finally wake up and start modernizing there compiler.

FPC having already implemented it, Embarcadero could have taken a look at FPC and keep compatibility that way. Why must Delphi always be different to FPC, when they are always the last one to implement something?? Delphi seem very uncooperative with FPC... the relationship being very one-sided (only from FPC's side). After all FPC is helping Delphi promote the language, so working together could be a win-win situation.

From the FPC side. Why must FPC developers always do things twice? Once,

long before Delphi, and then again, after Delphi implements it differently. That also means all FPC developers having used those features now have broken code - no backward compatibility for FPC developers itself??? That's a bit unfair don't you thing?

Simple solution for Delphi developers is simply to give up on Delphi and move over to FPC? Same language, similar features, always stay up-to-date, have better support and only one compiler to worry about! Our company did that 5 years ago and haven't regretted it for one second!

Really, that attitude is quite the turn off.

So is the Borland, CodeGear & Embarcadero attitude towards Free Pascal!

There there these incompatibilities causing me to avoid language features. I'd like to use them but just won't (Operator overloading

Simple solution as I mentioned - stick to one compiler only... Switch to FPC!

Regards,
- Graeme -

fpGUI Toolkit - a cross-platform GUI toolkit using Free Pascal http://opensoft.homeip.net/fpgui/

Reply by email

Florian Klaempfl
to Anthony Walter: On Sun, Nov 22, 2009 at 12:03 PM, Michael Van Canneyt Actually, you are pretty far off.…
Show quoted text 6 lines
type generic TList<T> = class end; See, we started a block {type} and introduced a keyword {generic} before the identifier {TList}. This unnecessarily breaks the pattern and is inconsistent.

It is a compromise made by the implementor. The proper solution would have been to throw away the type keyword and introduce generic sections (a generic is no type after all) but people didn't like this.

Anyways, no need to discuss this matter further on, I'am rather sure a patch implementing delphi syntax would be accepted maybe even with an optional generic modifier in FPC.

Reply by email

Michael Van Canneyt
to Anthony Walter: On Sun, Nov 22, 2009 at 12:03 PM, Michael Van Canneyt Actually, you are pretty far off.…
Anthony Walter wrote 22 lines
On Sun, Nov 22, 2009 at 12:03 PM, Michael Van Canneyt wrote: > Well, in > > Var >  A : Integer; > > The 'Var' is strictly speaking also redundant, as the : is used only in > variable declarations. But the 'var' makes it easier to read, and Pascal is > a verbose language. Additionally, the parsing is easier to do, as you know > what to expect next. By that rationale, the 'generic' keyword was deemed > appropriate when FPC made it's implementation. > > We'll resolve the incompatibility - remaining backwards compatible to FPC > itself - when someone finds the time and desire to do so. > > Or when someone from our beloved users sends us a patch to this effect. Michael, Actually, you are pretty far off. I've written a few parsers for Delphi and before generics it has ALWAYS gone like this:

I don't see how "I am far off" since you are saying the same as I am. Namely that the verbosity is a benefit.

None of this refutes the observation that - strictly speaking - var, type and whatnot are redundant, since it is perfectly possible to determine from

   A : Integer;

that this statement/line contains a variable declaration, so the 'Var' in front of it is not needed for the correct functioning of the compiler.

We only differ in that the 'generic' keyword interrupts the 'identifier expected' logic after the 'Type' keyword. So I can see the benefit of removing the generic keyword.

In fact, I'm a proponent of removing generics altogether, but that's another story :)

Michael.

Reply by email