Delphi Programming

and software in general.

Friday, July 8, 2011

Weird code snippet #1: Pseudobinary case statement

Curt Carpenter suggested a language addition for handing binary case logic.

That gave me this idea. Chalk it up as another weird code snippet from yours truly.

///<summary>> Convert array of booleans to a pseudobinary integer. 
///Good for up to 12 bits.</summary>
function BoolToInt(B: Array of Boolean):Integer;
var
  x : Boolean;
begin
  Result := 0;
  for x in B
  do begin
    Result := Result * 10;
    if x then Inc(Result);
  end;
end;

procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);
var
  ch : Char;
begin
  ch := Lowercase(Char(Key));
  case BoolToInt([ssShift in Shift, ssCtrl in Shift, ch='a', ch='x', ch='c', ch='v']) of
    011000: SelectAll;
    010100: Cut;
    010010: Copy;
    110010: Clone;
    010001: Paste;
  end;
end;


A slightly more tongue in cheek example:

procedure SexistTestLogic(const Cute, Funny, Smart: boolean);
begin
  case BoolToInt([Cute, Funny, Smart]) of
     000: Avoid;
     001: Admire;
     010,
     011: Befriend;
     100: Tolerate;
     101: HandleWithCare;
     110: Adore;
     111: Marry;
  end;
end;

Tuesday, June 14, 2011

Finding yourself in a property bind

From the wishful thinking department, I would love to be able to
var  
  Src: TSomeClass;
  MyObject : TBoundObject<Boolean>;
begin
  MyObject.Bind(Src, CompilerMagic(TSomeClass.SomeBooleanProperty));
end;
instead of
var  
  Src: TSomeClass;
  MyObject : TBoundObject<TSomeClass, Boolean>;
begin
  MyObject.Bind(Src, 'SomeBooleanProperty');
end;
Why? Because the first one is resilient to property renaming.
Until I can, I am stuck with using something similar to
var
  Src: TSomeClass;
  MyObject : TBoundObject<TSomeClass, Boolean>;
begin
  MyObject.Bind(Src,
    function (const Ref:TSomeClass):Boolean // reads the bound prop
    begin
      Result = Ref.SomeBooleanProperty;
    end,
    procedure (const Ref: TSomeClass; const Value:Boolean)  // writes the bound prop
    begin
      Ref.SomeBooleanProperty := Value;
    end);
end;
which actually has some benefits - such as being able to sanitize assigned values - but is way too verbose.

I wish...

Friday, April 8, 2011

Generics, Enumerated types and ordinal values

I wish this was a solution post, but it is a frustration post. I trying to figure out how I can use Ord() to convert an enumerated type to integer or cast an integer to an enumerated type using generics type arguments?

uses
  SysUtils,
  TypInfo;

type
  TSomeEnumType = (TheFirst, TheSecond, TheThird, TheFourth);

type
  TEnumGen<TEnumType> = class
    class function Name(const Enum:TEnumType):String;
    class function Value(const Ordinal:Integer):TEnumType;
  end;

class function TEnumGen<TEnumType>.Name(const Enum: TEnumType): String;
begin
  Result := Format('%s.%s', 
    [GetTypeName(TypeInfo(TEnumType)), 
     GetEnumName(TypeInfo(TEnumType), Ord(Enum)) // <-- Bombs
    ]);
end;

class function TEnumGen<TEnumType>.Value(const Ordinal:Integer):TEnumType;
begin
  Result := TEnumType(Ordinal); // <- Bombs
end;

Unfortunately there is no "enum" delimiter that can be used to tell the compiler that Ord() and casting of integers should be allowed for generic enumerated type arguments.