Where do you place your unit uses?

Where do you place your unit uses?

Over the years, I’ve come to preferring to place my uses in the Interface section only, even if its types, constants or methods only are used in the implementation section.

What is your practice, and why do you prefer one pattern over the others – or why would you recommend against one of these patterns?

unit Test;

interface

uses

ThisUnit, ThatUnit;

implementation

end.

vs

unit Test;

interface

uses

ThisUnit;

implementation

uses

ThatUnit;

end.

Scopes and names can really be deceiving.

Scopes and names can really be deceiving. A root class and a descendant class can both have public fields, properties and methods with the same name.

I really wonder why this doesn’t raise a warning or a even a hint?

(Berlin 10.1.x / Tokyo 10.2.x)

Output:

c: 1

TClass1:1

TClass1.PropTest:1

TClass2.Test:2

TClass2.PropTest:2

TClass1.Oops

Press any key:

Code:

program PublicScope;

{$APPTYPE CONSOLE}

{$R *.res}

uses

System.SysUtils;

type

TClass1 = class

public

Test: Integer;

constructor Create; virtual;

procedure Dump; virtual;

procedure Oops;

property PropTest:Integer read Test;

end;

TClass2 = class(TClass1)

public

Test:Integer;

constructor Create; override;

procedure Dump; override;

procedure Oops;

property PropTest:Integer read Test;

end;

{ TClass1 }

constructor TClass1.Create;

begin

Test := 1;

end;

procedure TClass1.Dump;

begin

Writeln(‘TClass1:’, Test);

Writeln(‘TClass1.PropTest:’, Test);

end;

procedure TClass1.Oops;

begin

Writeln(‘TClass1.Oops’);

end;

{ TClass2 }

constructor TClass2.Create;

begin

Inherited;

Test := 2;

end;

procedure TClass2.Dump;

begin

Inherited;

Writeln(‘TClass2.Test:’, Test);

Writeln(‘TClass2.PropTest:’, Test);

end;

procedure TClass2.Oops;

begin

Writeln(‘TClass2.Oops’);

end;

procedure Test;

var

c: TClass1;

begin

c := TClass2.Create;

try

Writeln(‘c: ‘, c.Test);

c.Dump;

c.Oops;

finally

c.Free;

end;

end;

begin

try

try

Test;

except

on E: Exception do

Writeln(E.ClassName, ‘: ‘, E.Message);

end;

finally

Write(‘Press any key: ‘);

Readln;

end;

end.

The ARC vs non-ARC situation adds yet another layer of complexity to creating cross platform code.

The ARC vs non-ARC situation adds yet another layer of complexity to creating cross platform code. The Linux compiler uses ARC – while Windows and OSX do not.

Guess what that does to the Linux support: It falls way down on the viability list for cross platform code for servers and services. Note that I don’t mind ARC – I just don’t get why they did not move to ARC for all platforms.

They could duplicate the libs, put the old ones into care & maintenance, and introduce

arc.system. *

arc.vcl. *

arc.data. *

and so forth…

The current situation is pretty much ridiculous.

/rant

Edit: Added what I wrote in the EMBT forums.

I do not expect my non-ARC code to behave on ARC. It is after all a very different life cycle management model.

If you expect to be able to take your non-ARC code and move to Linux without changes – you are delusional.

My gripe is that I can’t really go cross platform now with the non-ARC Win32/Win64/OSX compilers. There is no way I want to maintain code that have to deal with both ARC and non-ARC life cycle management. I want to be able to have cross platform code – across ALL platfoms – without having to think ARC/Non-ARC.

I believe an ARC compliant FMX/VCL/RTL and ARC compiler on Windows and OSX (in addition to the current non-ARC) would offer the most sensible migration path for those that want cross platform, since there is no chance that the iOS and Android compilers will go non-ARC.

For those that don’t want ARC, they have to sacrifice cross platform compatibility, and probably risk a deprecated platform in a few years.

For those that want cross platform compatibility, they may have to sacrifice a bit of performance with the added complexity of ARC.

Note that the current performance problem on Android looks a completely different issue – i.e. not ARC related, since the previous versions also used ARC on that platform.

Generics, records and typecasts = F2084 Internal Error: AV0DBFFBE9-R0000000C-0

Generics, records and typecasts = F2084 Internal Error: AV0DBFFBE9-R0000000C-0

// redux – not actual code

type

TKey = record

Index: Integer;

end;

TSomeClass = class abstract

procedure CopyTo(var Key: TKey); virtual; abstract;

procedure CopyFrom(var Key: TKey); virtual; abstract;

end;

TKeyValue = record

Key: TKey;

Value: T;

end;

TIndexList = TArray;

TKeyValueList = TArray<TKeyValue>;

TSomeClass = class(TSomeClass)

public type

TValueList = TArray;

private var

ValueList: TValueList;

procedure CopyTo(var Key: TKey); override;

procedure CopyFrom(var Key: TKey); override;

end;

procedure TSomeClass .CopyTo(var Key: TKey);

begin

TKeyValue(Key).Value := ValueList[Key.Index]; // OK

end;

procedure TSomeClass .CopyFrom(var Key: TKey);

begin

ValueList[Key.Index] := TKeyValue(Key).Value; // F2084 Internal Error: AV0DBFFBE9-R0000000C-0

end;

CopyTo/From called with a list of TKeyValue params.

I guess I was asking for it. Rewrote to use regular class objects.

consider

consider

TBase = class

public const

Snafu = 1;

public type

TInnerBase = class

Foo:Integer;

end;

public

procedure Bar(const Inner:TInnerBase); virtual; abstract;

end;

TDerived = class(TBase)

public

procedure Bar(const Inner:TBase.TInnerBase); override;

end;

procedure TDerived.Bar(const Inner: TBase.TInnerBase);

begin

Inner.Foo := Snafu;

end;

It nags me that I have to qualify TBase.TInnerBase, while I do NOT have to write TBase.Snafu; I wish I could drop the TBase. qualification part for types as well.

I keep butting my head into the lack of an enumeration generics constraint.

I keep butting my head into the lack of an enumeration generics constraint.

I can’t make generic arrays or set types from an enumeration, nor do operations on a variable of that type.

(Disclaimer: The code is for illustration only and may be incorrect or illogical)

TTaskFactory = class

type

TTaskClassArray: Array [T] of TTaskClass; //<– illegal

TTaskSet: Set of T; //<– illegal

private

class var FFactory: TTaskClassArray;

protected

FAllowedTasks: TTaskSet;

public

class procedure RegisterTask(const Id: T; aTaskClass:TTaskClass);

function MakeTask(const Id:T):TTask;

property AllowedTasks read FAllowedTasks write FAllowdTasks;

end;

class procedure TTaskFactory.RegisterTask(const Id: T; aTaskClass:TTaskClass);

begin

Log(‘Registered Task Id ‘+IntToStr(Ord(ID))); //<– illegal

FFactory[Id] := aTaskClass; //<– illegal

end;

function TTaskFactory.MakeTask(const Id:T):TTask;

begin

if Id in AllowedTasks //<– illegal

then begin

if Assigned(FFactory[Id]) //<– illegal

then Result := FFactory[Id].Create //<– illegal

else raise EProgrammerNotFound.Create(‘Forgot to register’);

end

else Result := nil;

end;

If only I could write:

TTaskFactory = class

TSoTaskType = (ttMakeItSo, ttSoBeIt, … ttSoWhat)

TSoTaskFactory = class(TTaskFactory);

I am sure there are other examples, but I really miss being able to do

declarations and operations like these in a generic class:

Arrays, sets, low/high, ord, in, pred/succ, and related operations.

Yes, there are better ways to do class factories, and I use them – but the Enumeration constraint would enable so many possibilities.