[fpc-pascal] Is it possible to specialize a generic class more than once, with different types, in the same unit?

Noel Duffy hobcraft-fpc at yahooxtra.co.nz
Sat Nov 15 09:10:38 CET 2014


I just started investigating the generics classes in fcl-stl for a
program that I'm writing. I haven't written anything using generics in
Free Pascal before, so this is all new to me. I am trying to
specialize THashMap to map both strings to unsigned integers and then
again to map integers back to strings, like so:

program maps;

{$mode objfpc}{$H+}

uses
    ghashmap, gutil;

type
    TStrHashingClass = class
        class function hash(a: AnsiString; b: SizeUint): SizeUint;
    end;

    TWordHashingClass = class
        class function hash(a: Word; b: SizeUint): SizeUint;
    end;

    TStringWordMap = specialize THashMap<AnsiString, Word, TStrHashingClass>;
    TWordStringMap = specialize THashMap<Word, AnsiString, TWordHashingClass>;

function StrHash(const S: string): Cardinal;
begin
    Result := 3; // yes I know, I'm trying to keep this short to illustrate my problem. I have a real hash function for my program.
end;

class function TWordHashingClass.hash(a: Word; b: SizeUint): SizeUint;
begin
    Result := a mod b;
end;

class function TStrHashingClass.hash(a: AnsiString; b: SizeUint): SizeUint;
begin
    Result := StrHash(a) mod b;
end;

var
    strtable: TStringWordMap;

begin
    strtable := TStringWordMap.Create;
    strtable['ábcdéf'] := 3;
    strtable.Destroy;
end.

This code will not compile:

$ fpc -Fu/usr/share/fpcsrc/2.6.4/packages/fcl-stl/src/ -FU.  maps.lpr
Free Pascal Compiler version 2.6.4 [2014/04/20] for x86_64
Copyright (c) 1993-2014 by Florian Klaempfl and others
Target OS: Linux for x86-64
Compiling maps.lpr
ghashmap.pp(111,16) Error: Incompatible types: got "THashmap$AnsiString$Word$TStrHashingClass.TPair" expected "THashmap$Word$AnsiString$TWordHashingClass.TPair"
ghashmap.pp(116,34) Error: Incompatible type for arg no. 1: Got "THashmap$Word$AnsiString$TWordHashingClass.TPair", expected "THashmap$AnsiString$Word$TStrHashingClass.TPair"
ghashmap.pp(160,29) Error: Incompatible types: got "Word" expected "AnsiString"
ghashmap.pp(161,41) Error: Incompatible types: got "AnsiString" expected "Word"
ghashmap.pp(168,27) Error: Incompatible type for arg no. 1: Got "THashmap$Word$AnsiString$TWordHashingClass.TPair", expected "THashmap$AnsiString$Word$TStrHashingClass.TPair"
ghashmap.pp(139,29) Error: Incompatible types: got "Word" expected "AnsiString"
ghashmap.pp(180,29) Error: Incompatible types: got "Word" expected "AnsiString"
ghashmap.pp(150,29) Error: Incompatible types: got "Word" expected "AnsiString"
ghashmap.pp(150,44) Error: Incompatible types: got "Word" expected "AnsiString"
ghashmap.pp(206,12) Error: Incompatible types: got "THashmap$AnsiString$Word$TStrHashingClass.TPair" expected "THashmap$Word$AnsiString$TWordHashingClass.TPair"
ghashmap.pp(227,11) Error: Incompatible types: got "AnsiString" expected "Word"
ghashmap.pp(232,13) Error: Incompatible types: got "Word" expected "AnsiString"
ghashmap.pp(242,39) Error: Incompatible types: got "AnsiString" expected "Word"
maps.lpr(44) Fatal: There were 13 errors compiling module, stopping
Fatal: Compilation aborted
Error: /usr/bin/ppcx64 returned an error exitcode (normal if you did not specify a source file to be compiled)

But, if I remove the definition of TWordStringMap on line 18 from the
type section, the code compiles just fine. It seems that fpc has
gotten confused by the second specialization and has confused the
two.

As I understand it, fpc generics work by writing placeholders into the
ppu which are then replaced with the specialized types. But how does
it handle cases where there's more than one specialization? Or is
there something else I've overlooked?

I am running fpc 2.6.4 on Debian stable and on Fedora 20, and both
display the same behaviour.




More information about the fpc-pascal mailing list