Record Helpers for Intrinsic Types

I guess that most of you already heart about it. With Delphi XE3 EMBT introduced record helpers for intrinsic types. E.g. Marco Cantu and Nick Hodges already blogged about it.

Just to explain what record helpers for intrinsic types are I will show an example.

program TestHelper;

{$APPTYPE CONSOLE}

{$R *.res}

type
  TMyHelper = record helper for string
  public
    function MyFunction: Integer;
  end;

{ TMyHelper }

function TMyHelper.MyFunction: Integer;
begin
  Result := 42;
end;

var
  sBuffer: string;

begin
  Writeln(sBuffer.MyFunction);
  Readln;
end.

As you can see the record helper allows you to write code that looks like calling a method of an intrinsic type instead of calling a function with the intrinsic type as an argument. This strategy is more object oriented and beautifies your code.

In Delphi XE3 EMBT already introduced some beautiful record helpers. The record helper for the string is the most important and powerful one. It has some really useful functions like Length, Equals, Format, IndexOf etc.. You can find it in the unit System.SysUtils.

Certainly you can write your own record helper for different types. You can also write a record helper for a string and write your own methods.

In the case you add your own helper unit to your uses clause and also System.SysUtils, the compiler only sees one record helper. The record helper which you add at last to your uses clause will win. Let’s have a look at an example:

unit MyHelper;

interface

type
  TMyHelper = record helper for string
  public
    function MyFunction: Integer;
  end;

implementation

{ TMyHelper }

function TMyHelper.MyFunction: Integer;
begin
  Result := 42;
end;

end.

With this unit you can replace the original string helper from System.SysUtils:

program TestHelper;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  System.SysUtils,
  MyHelper in 'MyHelper.pas';

var
  sBuffer: string;

begin
  Writeln(sBuffer.Length); //This line doesn't work any longer
  Writeln(sBuffer.MyFunction);
  Readln;
end.

Instead of replacing the original helper it would be nice to derive from it but this is simply not possible. This code doesn’t compile.

type
  TMyHelper = record helper(TStringHelper) for string
  end;

Although class helpers can be derived it is not possible for record helpers. I guess it is because records also cannot be derived.

This issue means that it is nearly impossible to extend the original record helpers. IMO it must be fixed with the next Delphi version.

Anyway, currently I can imagine only one strategy to extend the original record helpers. You have to write you own helper, you have to add all functions of the original one and then you have to call the original function inside your function. And don’t forget to declare them inline because of performance. Since your helper replaces the original one you have to write a call unit for the original helper.

Let’s have a look at an example. First write the caller unit:

unit MyStringCaller;

interface

type
  TMyStringCaller = record
  public
    class function ToUpper(const S: string): string; static; inline;
  end;

implementation

uses
  System.SysUtils;

{ TMyStringCaller }

class function TMyStringCaller.ToUpper(const S: string): string;
begin
  Result := S.ToUpper;
end;

end.

And then your own record helper:

unit MyHelper;

interface

uses
  System.SysUtils, MyStringCaller;

type
  TMyHelper = record helper for string
  public
    function Reverse: string;
    function ToUpper: string; inline;
  end;

implementation

uses
  System.StrUtils;

{ TMyHelper }

function TMyHelper.Reverse: string;
begin
  Result := ReverseString(Self);
end;

function TMyHelper.ToUpper: string;
begin
  Result := TMyStringCaller.ToUpper(Self);
end;

end.

Last but not least you can use your record helper:

program TestHelper;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  System.SysUtils,
  MyHelper in 'MyHelper.pas';

var
  sBuffer: string;

begin
  sBuffer := 'Hallo World!';
  Writeln(sBuffer.Reverse);
  Readln;
end.
Posted in Tips and Tricks | Tagged | Comments Off on Record Helpers for Intrinsic Types

IntraWeb and Session Timeout

This week I had to maintain an IntraWeb application. For those who are not familiar with IntraWeb it allows you to create a web application with Delphi. This means that you can design your web application with components and their properties in the same way as a Delphi desktop application. At runtime the controls render themselves, they create html code so that they look and feel in the same way as in the designer preview. That’s why the IntraWeb version that ships with Delphi is called the VCL for the Web.

I have to mention that there are huge differences between the various IntraWeb versions. In this case I used IntraWeb 12 in Delphi XE2 with full source code. In the version that ships with Delphi there are some limitations so that maybe the code I will show will not work. Currently Atozed is shipping a new IntraWeb version, the version 14.

If you create a new IntraWeb application you normally create two different apps: A stand-alone webserver for debugging purpose and a ISAPI dll that will be used in the real world.

The IntraWeb project wizard creates amongst others two important units: A server controller and a user session unit. Its is not surprising, the server controller controls your IntraWeb server app. Since web apps are stateless the user session gives you the possibility to save data that can be exchanged between your forms.

Let’s go back to the original problem: If your web apps shows some confidential data the app should get into a timeout after several minutes of inactivity. Therefore you can simply set the SessionTimeout property of the ServerController to a value in minutes after which your session gets into a timeout. In order to show the user a webesite after a timeout you can put a TIWURLResponderRedirect onto the ServerController and set the TimeoutResponse property to the TIWURLResponderRedirect. The TIWURLResponderRedirect has a property URL that will be shown in the case of a timeout.

This approach has two disadvantages: On the one hand the URL property points to a static website and on the other hand the client shows the timeout website not till then the client sends the next request to the server. The first point could be a deployment problem, the second point could be a problem since confidential data will rest on the screen.

That’s why I prefer a strategy in which the client polls the server, the server checks the inactivity time and if necessary redirects the client to a dynamic timeout website. Therefore I would like to place a timer on every form. The time polls the server, the server differs between the special timer request and a normal request, saves the last access in the session and redirects to the timeout form in the case the session has expired.

First I added the property LastAccess to the UserSession.

  TIWUserSession = class(TIWUserSessionBase)
  strict private
    FLastAccess: TDateTime;
  public
    property LastAccess: TDateTime read FLastAccess write FLastAccess;
  end;

Since Delphi supports visual inheritance I derived every form from a base form and placed a timer on it. In the timer event I checked if the session has expired.

procedure TfrmBase.tiSessionAsyncTimer(Sender: TObject; EventParams: TStringList);
const
  cMinuteToDateTime = 60 * 24;
begin
  if (Now - TIWServerController.UserSession.LastAccess) >= (TIWServerController.IWServerController.SessionTimeOut / cMinuteToDateTime) then
    TfrmTimeout.Create(WebApplication).Show;
end;

In the ServerController there is after every request an event fired in which I can decide if it was a normal request or a timer request.

procedure TIWServerController.IWServerControllerBaseAfterDispatch(Request: THttpRequest; aReply: THttpReply);
begin
  if (WebApplication <> nil) and (UserSession <> nil) and (Pos('TISESSION', Request.Query) <= 0) then
    UserSession.LastAccess := Now;
end;

In the timeout form I added a TIWURL component so that the user can navigate back to the login dialog. I set the URL property dynamically so that there is no problem concerning deployment.

procedure TfrmTimeout.IWAppFormCreate(Sender: TObject);
begin
  inherited;
  urlLogin.URL := WebApplication.ApplicationURL;
end;

procedure TfrmTimeout.urlWebWorkflowHTMLTag(ASender: TObject; ATag: TIWHTMLTag);
begin
  if Assigned(ATag) and (ATag.Params.IndexOfName('href') >= 0) then
     ATag.Params.Values['href'] := urlLogin.URL;
end;

Last bust not least I terminate the session manually (Please guys from Atozed don’t look at this code).

type
  THackApp = class(TIWApplication);

procedure TfrmTimeout.IWAppFormRender(Sender: TObject);
begin
  THackApp(WebApplication).FTerminated := True;
end;
Posted in Tips and Tricks | Tagged , | Comments Off on IntraWeb and Session Timeout

GlobalConsts.pas

Today, I found another example of a common mistake, a unit with global constants.

I guess most of you know this situation. There is a value that is used several times in a unit and you declare a constant for it. After a few minutes you recognize that you need the constant in another unit. Since it is difficult to decide to which unit the constant belong you simply create a constant unit for it.

With the growth of you project the number of constants in your constant unit increases. After a few weeks the unit contains hundreds of constants. In the current project I mentioned above there are about 600 constants in one unit.

As you can imagine there are some problems according to this unit:

  1. The constants belong to completely different subjects.
  2. It is difficult to decide if all constants are still in use (The compiler or tools like a Pascal Analyzer can help you).
  3. If you need a constant it is not easy to find it.
  4. With point 3 it is possible that you redeclare a constant.
  5. If you need in a new project only one single constant you have to add all the other constants to the project.

In order to avoid the problems from the beginning there are some small rules:

  1. Declare a constant in the unit where you need it.
  2. If possible declare the constant as a class constant.
  3. The visibility of a class constant should be as private as possible.
  4. If you share constants between units define constant units for each subject.
  5. Don’t mix constants in a constant unit that belong to different subjects.

Just to show the difference between normal constants and class constants, please look at these examples.

First you can define normal constants:
 

unit MyConsts;

interface

const
  cFuzzFactor = 1.23456789;

implementation

end.

Or you can also use class or record constants:

unit MyConsts;

interface

type
  TMyConstants = record
  public const
    cFuzzFactor = 1.23456789;
  end;

implementation

end.

The class constants allow you to play with the visibility, they are more object-oriented and they can be used like namespaces for constants. Therefore they are longer to type in your code. In the Delphi source code normal constants are used, In my code I’m using more and more class constants.

Posted in Tips and Tricks | Tagged | Comments Off on GlobalConsts.pas

ObjGuard

Sometimes it happens that I would like to convert a Delphi object to an interfaces. Interfaces offer some advantages.
On the one hand you can handle different objects that are not derived from a common hierarchy but share the same methods.
On the other hand interfaces are reference counted. You can use the reference counting as a poor man’s garbage collection.

Normally objects that are interfaced are derived from TInterfacedObject.
Let’s have a look at the implementation of TInterfacedObject in Delphi XE3.

...
  TInterfacedObject = class(TObject, IInterface)
  protected
{$IFNDEF AUTOREFCOUNT}
    FRefCount: Integer;
{$ENDIF}
    function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
    function _AddRef: Integer; stdcall;
    function _Release: Integer; stdcall;
...

function TInterfacedObject._AddRef: Integer;
begin
{$IFNDEF AUTOREFCOUNT}
  Result := AtomicIncrement(FRefCount);
{$ELSE}
  Result := __ObjAddRef;
{$ENDIF}
end;

function TInterfacedObject._Release: Integer;
begin
{$IFNDEF AUTOREFCOUNT}
  Result := AtomicDecrement(FRefCount);
  if Result = 0 then
    Destroy;
{$ELSE}
  Result := __ObjRelease;
{$ENDIF}
end;
...

You can see two things:

  1. Every interfaced object has to implement IInterface.
  2. EMBT will introduce a real garbage collection but currently a TInterfacedObject is simply reference counted.

Normally you have to decide whether an object is interfaced or not if you are implementing it, not if you are using it.
That’s why I introduced a small wrapper class for an object. The wrapper class is interfaced and offers full access to the underlying object.

unit ObjGuard;

interface

type
  IObjGuard<T: class> = interface(IInterface)
  ['{7FBC48DC-1ED4-450F-8418-64E0D942F115}']
    function get_Obj: T;
    property Obj: T read get_Obj;
  end;

  TObjGuard<T: class> = class(TInterfacedObject, IObjGuard<T>)
  strict private
    FObj: T;
    function get_Obj: T; inline;
  strict protected
    property Obj: T read get_Obj;
  public
    constructor Create(AObj: T);
    destructor Destroy; override;
  end;

implementation

uses
  System.Classes;

{ TObjGuard<T> }

constructor TObjGuard<T>.Create(AObj: T);
begin
  inherited Create;
  FObj := AObj;
end;

destructor TObjGuard<T>.Destroy;
begin
  FObj.Free;
  inherited Destroy;
end;

function TObjGuard<T>.get_Obj: T;
begin
  Result := FObj;
end;

end.

This makes the use of the object very simple. Just create an instance of the ObjGuard and the resulting interface offers access to the underlying object.
You can use it for example in records which don’t offer a destructor so that there must be a way to destroy object fields.

...
type
  TMyRecord = record
  strict private
    FStream: IObjGuard<TFileStream>;
    function get_Stream: TStream; inline;
  public
    constructor Create(const AFileName: string);
    property Stream: TFileStream read get_Stream;
  end;

...
constructor TMyRecord.Create(const AFileName: string);
begin
  FStream := TObjGuard<TFileStream>.Create(TFileStream.Create(AFileName, fmCreate));
end;

function TMyRecord.get_Stream: TStream;
begin
  Result := FStream.Obj;
end;

end.
Posted in Tips and Tricks | Tagged | Comments Off on ObjGuard

More About Records

Since records offer methods and properties they are often used to replace objects. This is possible if there is no need to use inheritance.

But there is a significant difference between both. References to objects are like pointers to a piece of memory whereas records are a piece of memory.

This makes a significant difference if you are using functions that return objects and records. Let’s have a look at one example.

program TestObject;

{$APPTYPE CONSOLE}

{$R *.res}

type
  TMyClass = class(TObject)
  strict private
    FNo: Integer;
  public
    property No: Integer read FNo write FNo;
  end;

  function Clone(const AClass: TMyClass): TMyClass;
  begin
    Result := AClass;
    Result.No := AClass.No + 1;
  end;

var
  pClass: TMyClass;
  pClone: TMyClass;
begin
  pClass := TMyClass.Create;
  try
    pClone := Clone(pClass);
    if pClone.No = pClass.No then
      Writeln('Clone hasn't cloned, it uses the same instance');
  finally
    pClass.Free;
  end;

end.

This is really simply. The clone function returns the reference itself. This means that it doesn’t clone, it uses the same instance!

Now, we will do the same with an record.

program TestRecord;

{$APPTYPE CONSOLE}

{$R *.res}

type
  TMyRecord = record
  strict private
    FNo: Integer;
  public
    property No: Integer read FNo write FNo;
  end;

  function Clone(const ARecord: TMyRecord): TMyRecord;
  begin
    Result := ARecord;
    Result.No := ARecord.No + 1;
  end;

var
  pRecord: TMyRecord;
  pClone: TMyRecord;
begin
  pClone := Clone(pRecord);
  if pClone.No <> pRecord.No then
    Writeln('Clone has really cloned');

end.

Now you can see the differences.

  1. There is no need to create a record, the record is simply there.
  2. With point 1 there is no need to destroy the record.
  3. A function that returns a record automatically creates a new one.
Posted in Tips and Tricks | Tagged | Comments Off on More About Records

TPath.Combine

I guess that everyone already had to solve this small issue. There are two variables, one with a path, the other with the filename and they have to be combined.
In the old Delphi world there is the function IncludeTrailingPathDelimiter from System.SysUtils.

procedure TMyObject.DoSomething;
var
  sFileName: string;
  sPath: string;
begin
  sFileName := 'Datei.txt';
  sPath := 'c:\temp';

  sFileName := IncludeTrailingPathDelimiter(sPath) + sFileName;
  Writeln(sFileName);
end;

With the unit System.IOUtils Delphi offers the new record TPath with the method combine.

procedure TMyObject.DoSomething;
var
  sFileName: string;
  sPath: string;
begin
  sFileName := 'Datei.txt';
  sPath := 'c:\temp';

  sFileName := TPath.Combine(sPath, sFileName);
  Writeln(sFileName);
end;

In our example both functions do the same. But if you look at the implementation of TPath.Combine you can see that it offers some other functionalities. TPath.Combine calls TPath.DoCombine that checks the valid chars and also checks if Path2 is already absolute. This means that the following code raises an exception.

procedure TMyObject.DoSomething;
var
  sFileName: string;
  sPath: string;
begin
  sFileName := 'Datei.txt';
  sPath := 'c:\temp' + #0;

  sFileName := TPath.Combine(sPath, sFileName);
  Writeln(sFileName);
end;

And this code does work.

procedure TMyObject.DoSomething;
var
  sFileName: string;
  sPath: string;
begin
  sFileName := 'c:\temp\Datei.txt';
  sPath := 'c:\temp';

  sFileName := TPath.Combine(sPath, sFileName);
  Writeln(sFileName);
end;
Posted in Tips and Tricks | Tagged | Comments Off on TPath.Combine

StringOfChar

This week I found a new interesting piece of code. Someone wanted to initialize a string with a special length of the same char.

procedure TMyClass.Init;
const
  cBufferLength = 100;
var
  I: Integer;
begin
  ...
  FBuffer := ''
  for I := 1 to cBufferLength do
    FBuffer := FBuffer + ' ';
  ...
end;

Come on guys, this is complete rubbish! In short words, a string is a record that allocs as much memory as the string needs. With this for loop the poor memory manager has to alloc a piece of memory 100 times! As you can image this is not fast and will also turn your memory into small pieces.

procedure TMyClass.Init;
const
  cBufferLength = 100;
var
  I: Integer;
begin
  ...
  SetFBuffer := ''
  for I := 1 to cBufferLength do
    FBuffer := FBuffer + ' ';
  ...
end;

A better solution would be to set the length of the string and then to set all chars.

const
  cBufferLength = 100;
var
  I: Integer;
begin
  ...
  SetLength(FBuffer, cBufferLength);
  for I := 1 to cBufferLength do
    FBuffer[I] := ' ';
  ...
end;

Or simply call the StringOfChar function.

const
  cBufferLength = 100;
var
  I: Integer;
begin
  ...
  FBuffer := StringOfChar(' ', cBufferLength)
  ...
end;
Posted in Tips and Tricks | Tagged | Comments Off on StringOfChar

(Ab)use of Try..Except

Today I found an example of the abuse of a try.. except block.

procedure TMyClass.DoSomething;
var
  sValue: string;
  iValue: Integer;
begin
  ...
  try
    iValue := StrToInt(sValue);
  except
    iValue := 0;
  end;
  ...
end;

The idea is simple. StrToInt converts a string to an integer as long as the string contains an integer value. If not an exception will be raised.
This exception will be caught because of the try..except block and 0 will be assigned to the variable iValue.

Please, never write code like this! The problem is that all kind of exceptions will be caught including EAccessViolation, EOuOfMemory etc..
Certainly is is better to use a function instead of StrToInt that doesn’t throws an exception but allows you to use a default value.

procedure TMyClass.DoSomething;
var
  sValue: string;
  iValue: Integer;
begin
  ...
  iValue := StrToIntDef(sValue, 0);
  ...
end;

If there is no other way, if you have to call a function that possibly raises an exception then catch only this particular exception. In our example we have to catch the EConvertError.

procedure TMyClass.DoSomething;
var
  sValue: string;
  iValue: Integer;
begin
  ...
  try
    iValue := StrToInt(sValue);
  except
    on E: EConvertError do
      iValue := 0;
  end;
  ...
end;
Posted in Tips and Tricks | Tagged | Comments Off on (Ab)use of Try..Except

Records

Because of my post about the Switches I would like to mention some things about records. Records are are nice way to do things in an object-oriented way without the overhead of real objects. In the unit System.IOUtils you can find several examples of records.

...
unit System.IOUtils;
...
  TDirectory = record
  public
...

Certainly you have to deal with some disadvantages:

  1. No inheritance. If you need inheritance then use objects.
  2. The constructor needs at least one argument. I guess it is because there is no need to create an instance of a “normal” record.
  3. No destructor. Records are destroyed automatically so that it is not possible to define a destructor.

For the point 1 there is nothing you can do but for the two other pints there is a workaround.

  TRttiContext = record
  ...
  public
    class function Create: TRttiContext; static;
    procedure Free;
    ...
  end;

As you can see it is possible to define a class function for the constructor and a method for Free so so that you can use the record in the way you are used to.

var
  pContext: TRttiContext;
begin
  pContext := TRttiContext.Create;
  try
    ...
  finally
    pContext.Free;
  end;
end;
Posted in Tips and Tricks | Tagged | Comments Off on Records

Naming of Constants

Normally constants improve the readability and maintainability of your code. One example is the minimum value of a single. You can find it in the unit System.Math:

...
const
  MinSingle   =  1.4012984643248170709e-45;
...

Instead of writing the float value it is easier and more readable to use the MinSingle constant.
But today I found a way how to do this in a very bad way. Someone had to parse a text file. One feature was that is was possible to delete values. Therefore the writer of the file used a special value, a “*”. That’s why I found the following code:

const
  cStar = '*';
var
  sValue: string;
  ...
begin
  ...
  if sValue = cStar then
    DoDeleteValue
  ...
end;

This is complete nonsense! If you really have no idea how to name your constant then simply don’t use it! The name always should refer to the meaning of the constant and not to the content.
Maybe something like this is better:

const
  cDeleteValue = '*';
var
  sValue: string;
  ...
begin
  ...
  if sValue = cDeleteValue then
    DoDeleteValue
  ...
end;

 

Posted in Tips and Tricks | Tagged | Comments Off on Naming of Constants