About the author
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] of SpriteClass = ( SpriteNothing, SpriteStone, SpriteGround, SpriteGhost180, nil, SpriteDiamond, SpriteWall, SpriteGhost90L, nil, SpriteUvStone, SpriteDigger, SpriteGhost90LR, SpriteExit, nil, 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.