Saturday, October 15, 2016

Delphi Perspectives: Kick-Start or the Last Kicks?

I've received another e-mail offer from Embarcadero to upgrade my Delphi 10.1 Berlin Starter Edition to Professional for €749 (claiming to save over €2000). The offer is valid this weekend only and includes:
  1. Delphi 10.1 Berlin Professional upgrade
  2. Mobile Add-On Pack
  3. "Bonus Packet" with VCL and FireMonkey Styles, Konopka VCL Controls and Marco Cantù's Object Pascal Handbook
After Embarcadero shut down their R&D centers (with no public statement) and let go of people like Allen Bauer and David Intersimone I start wondering: Is this the beginning of the final sell-out? On a more positive note, the new General Manager mentioned in an interview (PDF) that they wanted to attract new developers and get back into education. Hints of this happening are already here.

Let's see what happens...

Sunday, September 11, 2016

Potential Deadlocks in Parallel.For

Recently, I've come across some C# code deadlocking quite reproducibly while executing some tasks using Parallel.For method. The seemingly innocuous code lead to an "obscure situation" exactly as described in this blog post by Stephen Toub:
Does Parallel.For use one Task per iteration?
...iterations are handed out in indivisible chunks, and only one thread is involved in the processing of a particular chunk. This has implications for interdependencies between iterations. If iteration i blocks waiting for iteration i + 1 to be completed, and iterations i and i + 1 are both allocated to the same chunk, the loop will likely deadlock. The thread processing those iterations will block processing iteration i, but as that thread is also responsible for processing iteration i + 1, iteration i + 1 will never get processed and iteration i will never unblock.
The problem in this case was exactly as described above: there were blocking wait dependencies between the tasks in a producer/consumer pattern. The solution (once the problem was clear) was relatively simple: don't rely on the default partitioning of Parallel.For; provide your own to avoid the potential deadlock.

A good framework or library can provide you with a good-enough solution in a large-enough percentage of possible use cases (probably making some compromises to achieve that goal). Don't expect a pre-fabricated solution to solve all your problems out of the box; There is no silver bullet.

Here's some interesting reading about the Parallel.For implementation in .NET and trade-offs between simplicity, overheads, and load balancing:
Patterns of Parallel Programming (Understanding and Applying Parallel Patterns with the .NET Framework and Visual C#)

Friday, September 02, 2016

No runtime type information on interface properties

You might have tried to decorate an interface property in Delphi with a custom attribute like in this question on StackOverflow.

Unfortunately, that won't work, as I explained in my answer. No runtime type information is generated for interface properties so your attribute will have no effect, even though there's no compiler warning. You can try the code below which demonstrates it.

Of course, if you can prove me wrong or have another idea please let me know in a comment here. Thanks!

Here's the code:

program Test;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  System.SysUtils,
  System.Rtti;

type
  TTestAttribute = class(TCustomAttribute)
  private
    FName: string;
  public
    constructor Create(const AName: string);
    property Name: string read FName;
  end;

  [TTestAttribute('AtInterface')]
  ITestInterface = interface(IInvokable)
    ['{92A8107E-B40E-4786-A02E-251EA0DB3937}']
    [TTestAttribute('AtMethod')]
    function GetValue: string;
    [TTestAttribute('AtMethod')]
    procedure SetValue(const AValue: string);
    [TTestAttribute('AtProperty')]
    property Value: string read GetValue write SetValue;
  end;

constructor TTestAttribute.Create(const AName: string);
begin
  inherited Create;
  FName := AName;
end;

procedure ShowAttributes(const Attributes: TArray<TCustomAttribute>);
var
  Attr: TCustomAttribute;
begin
  for Attr in Attributes do
    if Attr is TTestAttribute then
      Writeln(Format('%s(''%s'')', [Attr.ClassName, TTestAttribute(Attr).Name]))
    else
      Writeln(Attr.ClassName);
end;

procedure Main;
var
  Ctx: TRttiContext;
  AType: TRttiInterfaceType;
  Attributes: TArray<TCustomAttribute>;
  Method: TRttiMethod;
  Prop: TRttiProperty;
begin
  Ctx := TRttiContext.Create;
  AType := Ctx.GetType(TypeInfo(ITestInterface)) as TRttiInterfaceType;
  Writeln(Format('Attributes on the interface ''%s'':', [AType.Name]));
  ShowAttributes(AType.GetAttributes);
  Writeln;
  for Method in AType.GetMethods do
  begin
    Writeln(Format('Attributes on method ''%s'':', [Method.Name]));
    ShowAttributes(Method.GetAttributes);
  end;
  Writeln;
  for Prop in AType.GetProperties do
  begin
    Writeln(Format('Attributes on property ''%s'':', [Prop.Name]));
    ShowAttributes(Prop.GetAttributes);
  end;
end;

begin
  try
    Main;
    Readln;
  except
    on E: Exception do
    begin
      ExitCode := 1;
      Writeln(Format('[%s] %s', [E.ClassName, E.Message]));
    end;
  end;
end.

This produces the following output:

Attributes on the interface:
TTestAttribute('AtInterface')

Attributes on method 'GetValue':
TTestAttribute('AtMethod')
Attributes on method 'SetValue':
TTestAttribute('AtMethod')

Already the call to AType.GetProperties returns an empty array; there is no RTTI for interface properties.