Skip to content

Delphi Conundrum - What Am I Doing Wrong?

So, I'm working on some of the rendering classes for my latest project and I've encountered an interesting issue that I can't explain and I'd greatly appreciate it if someone could explain to me what it is I'm doing wrong because I just can't see it.

These are the code snippets that I believe are relevant (hopefully it's obvious, but I've significantly simplified them leaving only what I think is relevant)....

ORE.Renderer.Classes.TextureAtlas.pas
unit ORE.Renderer.Classes.TextureAtlas;

interface

uses
  ORE.BaseClasses.Objects;

type
  TTextureAtlas = class(TBaseObject)
  public
    /// <summary>
    ///   Create a texture in the current rendering context.
    ///   This will be the entire atlas texture.  The caller is responsible
    ///   for cleaning up the texture in OpenGL.
    /// </summary>
    function generateTextureForCurrentContext:pointer; virtual; abstract;
  end;

  TTextureAtlasClass = class of TTextureAtlas;

TBaseObject is descended from TObject and just includes some debugging/logging code I want in all my objects.

ORE.Renderer.OGL.TextureAtlas.pas
unit ORE.Renderer.OGL.TextureAtlas;

interface

uses
  ORE.Renderer.BaseClasses.TextureAtlas;

type
  TTextureAtlasOGL = class(TTextureAtlas)
  public
    function generateTextureForCurrentContext:pointer; override;
  end;
ORE.Renderer.BaseClasses.Renderer.pas
unit ORE.Renderer.BaseClasses.Renderer;

interface

uses
  ORE.BaseClasses.Objects,
  ORE.Renderer.Classes.TextureAtlas;

type
  TRenderer = class(TBaseObject)
  protected
    fAtlasClass: TTextureAtlasClass;
  end;
ORE.Renderer.OGL.Renderer.pas
unit ORE.Renderer.OGL.Renderer;

interface

uses
  ORE.Renderer.BaseClasses.Renderer,
  ORE.Renderer.OGL.TextureAtlas;

type
  TRendererOGL = class(TRenderer)
  public
    constructor create;
  end;

implementation

constructor TRendererOGL.create;
begin
  inherited create;

  // This line... I get E2010 Incompatible types
  // TTextureAtlasClass <> class of TTextureAtlasOGL
  fAtlasClass := TTextureAtlasOGL;
end;

The exact message I get is this:-

E2010 Incompatible types: 'TTextureAtlasClass' and 'class of TTextureAtlasOGL'

I understand this error, but what I don't get is how this use case is any different from that of TCollectionItem for example where the TCollection constructor expects a parameter of type TCollectionItemClass, which is defined as:-

TCollectionItemClass = class of TCollectionItem

And my collection item is TMyCollectionItem = class(TCollectionItem) and then I can create a collection like this:-

TCollection.create(TMyCollectionItem)

Why does this work (and I've included some code to test this) yet my code doesn't? I've done this before and had zero issues but for some reason the compiler just doesn't like this code.

Please help as my current work around is dirty (TTextureAtlasClass = TClass) and I'd really like to know what I've got wrong. I have also tried doing this by passing the class into the TRenderer constructor like TCollection but I still get this error.

Why?????

The Solution

All I can say is DOH!!! Notice this subtle difference...

ORE.Renderer.OGL.TextureAtlas.pas
1
2
3
4
5
6
unit ORE.Renderer.OGL.TextureAtlas;

interface

uses
  ORE.Renderer.BaseClasses.TextureAtlas;
ORE.Renderer.BaseClasses.Renderer.pas
1
2
3
4
5
6
7
unit ORE.Renderer.BaseClasses.Renderer;

interface

uses
  ORE.BaseClasses.Objects,
  ORE.Renderer.Classes.TextureAtlas;

This issue is a direct result of me changing my mind on naming conventions and source file layout.

There were two units... ORE.Renderer.BaseClasses.TextureAtlas and ORE.Renderer.Classes.TextureAtlas that both defined a class TTextureAtlas and both define a class reference type TTextureAtlasClass. TRenderer was using one whilst TRendererOGL where the error was occuring was using the other.

That will teach me for not sorting out my source files and being doubly careful when checking my code. DOH!!!