Lutz Roeder originally wrote Digger in C# many years ago. In 2004, I ported it first to Delphi.NET, and then to Delphi for Win32. In February 2009, I ported it to the Android platform.
Today, I'll discuss a pattern that I worked on when porting C# to Delphi.
In Digger's C# code, the following code sequence is seen.
Type[] t = { typeof(Nothing), typeof(Stone), typeof(Ground), typeof(Ghost180), null, typeof(Diamond), typeof(Wall), typeof(Ghost90L), null, typeof(UvStone), typeof(Digger), typeof(Ghost90LR), typeof(Exit), null, typeof(Changer), typeof(Ghost90R) }; SetSprite(x, y, (Sprite) Activator.CreateInstance(t[id]));
Type[] t = { typeof(Nothing), typeof(Stone), typeof(Ground), typeof(Ghost180), null, typeof(Diamond), typeof(Wall), typeof(Ghost90L), null, typeof(UvStone), typeof(Digger), typeof(Ghost90LR), typeof(Exit), null, typeof(Changer), typeof(Ghost90R) };
MSDN explains typeof as such: "The typeof operator is used to obtain the System.Type object for a type". The intention of the above code is to create an instance of a Sprite descendent, depending on the id given.
When translating C# to Delphi, I used the Class-Reference (or metaclass) pattern. The code sequence was translated as such in Delphi (both .NET and the Win32 target):
type
SpriteClass =
class
of
Sprite;
const
t:
array
[
0..15
]
SpriteClass = (
SpriteNothing, SpriteStone, SpriteGround, SpriteGhost180,
nil
,
SpriteDiamond, SpriteWall, SpriteGhost90L,
, SpriteUvStone,
SpriteDigger, SpriteGhost90LR, SpriteExit,
, SpriteChanger,
SpriteGhost90R);
var
ASprite: Sprite;
begin
ASprite := t[id].Create;
SetSprite(x, y, ASprite);
end
;
In the parent Sprite class, I declared a virtual constructor, and in each of the Delphi classes, I had to override the virtual constructor.
For the Android port, when translating Delphi to Java, I used the class literals pattern.
final Class<?>[] t = { Nothing.class, Stone.class, Ground.class, Ghost180.class, null, Diamond.class, Wall.class, Ghost90L.class, null, UvStone.class, Digger.class, Ghost90LR.class, Exit.class, null, Changer.class, Ghost90R.class };Class<?> c = t[id];if (c!=null) SetSprite(x, y, (Sprite) c.newInstance());
In each of the descendent Java classes, I did not provide any constructors, since by default, Java has a rule such that "The compiler automatically provides a no-argument, default constructor for any class without constructors."
So there you go! A way of creating an instance of a class in 3 different languages!
Link to the Android application Link to the Digger Delphi Windows application
A method pointer is now the same as a global procedure, ie, procedure of object = procedure.