6

I'm on D2010, on which I have to stay until the 64 bit comes out.

With the generics, pointers to generic types are not supported, and I would find them to be very useful indeed. I read elsewhere on SO (2009 posting) Sir Barry Kelly thought this may well change in future. Does anyone know if this is supported in XE?

If not, I really hope they get put into XE2.

Thanks.

RRUZ
  • 134,889
  • 20
  • 356
  • 483
csharpdefector
  • 813
  • 8
  • 19

3 Answers3

5

On XE (2011):

This works:

type
  TTest1<T> = record
    FX : T;
  end;

  TTest2<T> = array of T;

This won't work:

type
  TTest3<T> = ^TTest1<T>;
  TTest4<T> = ^TTest2<T>;
  TTest<T> = ^T;

So pointers to generics are not yet possible.

But you can do the following:

type
  TMyClass = class
  public
    class function GetAddr<T>(const AItem: T): Pointer;
    class function GetP<T>(const APtr: Pointer): T;
  end;

class function TMyClass.GetAddr<T>(const AItem: T): Pointer;
begin
  Result := @AItem;
end;

class function TMyClass.GetP<T>(const APtr: Pointer): T;
begin
  Result := T(APtr^);
end;

You can't have generic functions, but you can have generic methods.

So with this you are able to have pointers to generics, but remember that you have no type safety using this dirty technique.

Toon Krijthe
  • 52,876
  • 38
  • 145
  • 202
2

NOTE: The following answer is wrong, starting as it does from an flawed premise! Rather than redact the entire thing to save my blushes, I have left it intact so that the comments highlighting the error make sense,

How can this possibly be supported safely ?

Given (if this is what you have in mind, which I think it is):

  type
    TFoo<T> = class end;
    PFoo<T> = ^TFoo<T>;

Then if we have:

  var
    a, b: TFoo<T>;
    p: PFoo<T>;

  a := TFoo<String>.Create;
  b := TFoo<Integer>.Create;

Then both of the following would be permissible:

  p := @a;

  p := @b;

At any given time p might dereference to any TFoo of T, but at any given time it can only ever reference a specific T. I cannot see any type-safe compile time mechanism for ensuring that code dereferences p correctly.

One way to get around this issue (not a limitation of the compiler, but a limitation of trying to express something in a type safe way for which type safety simply cannot be expressed) would be to create type-specific derivatives of these types and use those. At the point at which you wish to dereference you are almost certainly going to know the type T anyway:

  type
    TFoo<T> = class end;

    TFooString = TFoo<String>;
    PFooString = ^TFooString;


  var
     p: PFooString;


  a := TFoo<Integer>;
  b := TFoo<String>;


  p := @a;  // Should not compile
  p := @b;  // This is OK

This is possible even in Delphi 2010.

However, worryingly, in investigating this I find that:

  p := @a;  // Should not compile

DOES in fact compile. Which strikes me as wrong. VERY wrong. And could point to (yet) another flaw in the generics implementation in Delphi.

Here be dragons...

Deltics
  • 22,162
  • 2
  • 42
  • 70
  • +1 Very good write up. Have you QC'd your finding of what does but should not compile? – Marjan Venema Jan 08 '11 at 21:29
  • @Marjan : Nope. First of all, I don't have access to XE to confirm that the bug still exists - if it has already been fixed in XE then there's no point reporting it against 2010 since there won't be any further fixes for 2010 released. Secondly, it may be a consequence of the fact that the generic class TFoo doesn't actually reference the T type. If it did, the compiler may be more strict - I haven't tested this hypothesis however (fwiw, imho it should fail to compile in any event). But hence my observation that it "could" point to a flaw, not that it definitely does. :) – Deltics Jan 08 '11 at 21:38
  • 2
    The @ operator is not typed by default in Delphi; that's why you're not getting diagnostics. Turn on with `{$T+}`. Moreover, it is perfectly possible in principle to have generic pointers in Delphi (though they're not implemented). Your first set of example code is all wrong. A (theoretical) `p: PFoo` would be compatible with the addresses of locations of type `TFoo`, where we're talking about the same `T`. So if p is of type `PFoo`, it would be compatible with `@a` iff `a: TFoo`, but not `a: TFoo`. – Barry Kelly Jan 08 '11 at 21:43
  • Aha, yes Barry thanks. 2nd cup of coffee this morning clearly is needed. :) – Deltics Jan 08 '11 at 21:50
  • 1
    -1 As Barry points out this analysis is flawed. I honestly can't believe that anyone in their right mind runs in {$T-} mode. Does anyone really do it? And if so, why? – David Heffernan Jan 08 '11 at 21:59
  • @Barry suppl.: Typed pointers make things worse actually... defining TFooString and PFooString, attempting to assign a ref to a TFooString to a variable of type PFooString yields an incompatible types error, when the types clearly are compatible. This perhaps is a manifestation of the current lack of support in this area bemoaned by the original question ? – Deltics Jan 08 '11 at 21:59
  • @David - 2 reasons: 1, because, as Barry points out, it's the default. 2, because the typed @ operator behaviour isn't OO aware. A variable of type ^TForm cannot be assigned a ^T-My-Form even where TMyForm = class(TForm), which can make working with a typed @ operator a real PITA. – Deltics Jan 08 '11 at 22:06
  • @Deltics It's better to have the type system working with you as opposed to it turning a blind eye to everything you do! – David Heffernan Jan 08 '11 at 22:08
  • 1
    @David: When working with pointers you should know what you're doing... if you need the compiler handl-holding you along the way then you probably shouldn't be messing with pointers in the first place. I agree that the type system should work with you, the problem is that the typed @ operator has only a partial awareness of the type system, and when you run into that limitation it positively hinders, rather than helps. – Deltics Jan 08 '11 at 22:11
  • @Deltics Calling type checking "hand holding" seems a bit patronising and also very unwise. Surely you wouldn't want the compiler letting you assign anything to anything else. I like running $T+ and most of the time when I use the @ operator it's no problem. When the compiler complains I either fix my bug, or use explicit cast after analysing why I want to go outside the type system. Anyway, given the above answer it seems that you perhaps would benefit from a little hand holding from time to time! ;-) – David Heffernan Jan 08 '11 at 22:26
  • @ David - my initial error stemmed from the fact that I don't use generics because I can be more productive without them, avoiding having to waste time finding my way around their limitations and bugs, and producing code as a result that is more easily understood by more people. I've never once fallen foul of an incorrectly typed pointer p - or use of one - in my code. The fact that you run into errors with it turned on simply confirms that you *do* need the safety net that typed @ provides. That doesn't mean everyone needs it or that people not using it should "beggar belief". – Deltics Jan 08 '11 at 22:58
  • @deltics you're probably right I certainly wish I was so talented that I never made mistakes. I am envious of you for that. – David Heffernan Jan 08 '11 at 23:04
  • I didn't say I don't make mistakes - evidence: this answer!! But I've never made the mistake that this optional compiler feature is designed to catch, so I do not choose to enforce upon myself the additional limitations and constraints that limit type compatibility *beyond* that enforced by the type system !!! (a TForm var can hold a reference to an instance of a derived class, but a PForm *cannot* hold a pointer to such a reference, not without additional syntactic noise in the code to coerce the compiler into accepting what the type specification *defines* as acceptable !! – Deltics Jan 09 '11 at 04:38
  • @David: Your comments and answers are usually very worthwhile but do you really need to turn on the sarcasm so readily and frequently? It's not just in these comments here. I have noticed it in other comments and answers as well. Your answers and comments would be even better and a lot more effective if you left out the tone of voice so people wouldn't be pushed into defensive mode... – Marjan Venema Jan 09 '11 at 09:35
  • @marjan thanks for this and you are probably right of course. In this instance I think the sarcasm was my own defence mechanism but you are right that it adds nothing of value. – David Heffernan Jan 09 '11 at 09:57
  • "*DOES in fact compile*" -- still the case with Tokyo UIpdate 2. Take that, type safety! Cost me 2+ hours today. – JensG Jan 19 '18 at 13:46
2

Afaik pointers to generic types are only supported nested inside the generic.

Type
   tbwimagegen <T > = Class(TBaseImage)
             Type
                TLocalType =tbwimagegen <T>;
                BaseUnit = T;
                RefT= ^BaseUnit;
              end;

I use this so that I can easily switch image processing code (T=8,16,32-bit integer or RGBA record) by type. I just switch the specialization, and the code, that uses the nested types, adapts.

Of course, as with all generics, you can only use the specialized type, since no code is generated for any code with generic, non-specialized types. (it is only saved till specialization time)

Update: I ran into http://qc.embarcadero.com/wc/qcmain.aspx?d=99703 unfortunately.

Marco van de Voort
  • 25,628
  • 5
  • 56
  • 89
  • Note that [QualityCentral has now been shut down](https://community.embarcadero.com/blogs/entry/quality-keeps-moving-forward), so you can't access `qc.embarcadero.com` links anymore. If you need access to old QC data, look at [QCScraper](http://www.uweraabe.de/Blog/2017/06/09/how-to-save-qualitycentral/). – Remy Lebeau Jun 09 '17 at 17:57
  • I've tracked them over the years by downloading trials. In Seattle my various reports were fixed (actually in XE7, but a regression obscured it). and a generic version of this code works : https://stackoverflow.com/questions/848025/rotating-bitmaps-in-code – Marco van de Voort Jun 10 '17 at 10:43