Hi! I've been following the generic discussion with great interest. Here are 
some of my thoughts.

Florian Klaempfl wrote:
- we'll use a syntax as close as possible to Chrome, e.g.
type
  TList<T> = class
    ...
  end;

I greatly favor this syntaxis above the generic-modifier. It will look at a lot 
more familiar to most programmers (due to e.g. C++ and Java), is more compact 
and moreover likely to be compatible with other implementations (Chrome, rumors 
about Delphi 11).

I assume this also means that the generic type identifier has to be included in 
the method implementation, e.g.

TList<T>.Add(AValue: T);
 begin
   ...
 end;

This would also allow overloading of generics, i.e. having (generic) classes with different 
numbers of type parameters, but the same name. E.g. having both a TList and a 
TList<T>. (though a declaration like TList = TList<pointer> could easily solve 
this in this case)

How will we deal with restrictions on the type of a generic parameter? Chrome 
does this with for example

 Dictionary<Key, Value> = public class
   where Key is IComparable, Key has constructor, Value is Component;

And will it be possible to have type dependent specializations? E.g.

TList<T>.Add(AValue: T);
 ...
TList<T: TObject>.Add(AValue: T);
 ...

This can allow for efficient implementations for certain specific types while 
using the same name. Though it more or less violates the write-once advantage 
of generics, efficiency and type name uniformity is still available I think.

- instantiation will be only possible in declaration blocks, not in code
blocks:
possible:
var
  mylist : TList<integer>;
const
  mylist : TList<integer> = nil;
type
  mylist = TList<integer>;
forbidden:
procedure p(mylist : TList<integer>);
begin
  ...
  mylist:=TList<integer>.create;
  ...
end;

This seems like a smart and sufficient solution to avoid the problem of parsing 
< tokens in code blocks.

On the other hand, programmers will like it (a lot) more if they don't need to 
separately define a type for every generic instantiation. Is the 
token-lookahead approach proposed elsewhere in this thread not a sufficient 
solution? If it is not very easy, or if we are quite unsure about this for now, 
perhaps we can postpone the implementation of in-code(block) generic 
instantiation to a later time and first implement generics as above.

Maybe we need an exception to this when supporting sub routine templates:
procedure<T> p(mylist : TList<T>);
begin
...
end;
but this doesn't lead to an ambigious syntax.

Because you can easily decide that a T following a < in the code is a generic 
parameter? (I assume you also allow TList<T>.Create in the code block ... above?)

- instantiation steps which require code generation are done after main
program compilation based on information saved in the unit files, this
has some advantages:
- several equal instantiations require only one specialisation

So TList<TSomeNiceObkect> and TList<TSomeOtherNiceObject> share the same code 
if nothing particular of the types TSomeNiceObject and TSomeOtherNiceObject is used in the 
generic?

That is indeed quite important I think. Container classes often do not assume 
anything about the class they store, and otherwise we would get a lot of 
duplicate code in the resulting executables (for all different classes, which 
in fact all are 4 (or 8) byte pointers).

- it's possible to setup an symbol environment as it has been used in
the template definition, so the cyclic unit use problem is void it
requires though that a lot symbols of the implementation part of a unit
must be written to the unit file if the unit contains a template definition

Will a generic implementation have access to procedures visible at the location where the 
generic is instantiated? It might seem at first to be a useful restriction to disallow 
this, because otherwise a TList<TMyType> in unit1 could need another specialisation 
than TList<MyType> in unit2. But on the other hand, we might just want to allow it! 
Example:

In the (imaginary) unit containers there might be a TSortedList<T> class, which uses the 
< operator on T. In yourunit you define a type TYourType and an operator < operating on 
TYourType. If you now want use TSortedList<TYourType> in yourunit, it will need to pick up 
the operator defined in yourunit, which is not visible in the unit containers.

Similar questions might arise with respect to code for Hashing a specific type for 
e.g. THashMap<Key, Value>. Possible solutions appearing in my mind are that
(1) a user has to write a function Hash(O: TYourType):integer; for every TYourType, or (2) adding Hash to TObject (like in Java) or to some class of interface (e.g. IHashable), where we need to be able to impose certain conditions on the generic parameters's types as in Chrome (see above).

Note: Java has the Comparable interface and does not allow overloading of 
operators like < iirc (but C++ does of course).

Regards,

Bram
_______________________________________________
fpc-devel maillist  -  fpc-devel@lists.freepascal.org
http://lists.freepascal.org/mailman/listinfo/fpc-devel

Reply via email to