FireDAC WTF of the day ;)

FireDAC WTF of the day 😉

Conn := TFDConnection.Create(nil);

Conn.DriverName := FireDriverLink.BaseDriverId;

// The above lines were actually in a function in the worker pool

for tgt in targetlist

do begin

  Conn.Params.Clear;

  Conn.Params.Values[‘Server’] := tgt.Host;

  Conn.Params.Values[‘Database’] := tgt.DatabaseName;

  Conn.Params.Values[‘OSAuthent’] := ‘No’;

  Conn.Params.Values[‘User_Name’] := tgt.UserName;

  Conn.Params.Values[‘Password’] := tgt.Password;

  Conn.Connect;

  Exception: Driver name not set.

I added the above clear since I would be reusing the connection for multiple databases in a loop, and it took me a few rounds in the debugger before I figured out that the property mapped into the params list instead of a property field of it’s own.

Lesson learned.

Wait… WHAT!?

Wait… WHAT!?

Exercise for the reader – how much faster would this be with a hash table or binary search?

unit Data.Db;

function TFields.FindField(const FieldName: string): TField;

var

  I: Integer;

  HashValue: Cardinal;

begin

  if FList.Count > 0 then

  begin

    HashValue := TNamedItem.HashName(FieldName);

    for I := 0 to FList.Count – 1 do

    begin

      Result := FList.Items[I];

      if (Result.FFieldNameHashValue = HashValue) and

         (AnsiCompareText(Result.FFieldName, FieldName) = 0) then

        Exit;

    end;

  end;

  Result := nil;

end;

Generics and constructors

Generics and constructors

Fair enough, if you qualify the type to require a constructor

TMyClass = class

private

  property Inner: T;

public;

  procedure InnerCreate;

end;

you must have a parameterless constructor to instantiate T.

TMyClass.InnerCreate;

begin

   Inner := T.Create;

end;

but – If you qualify the type of T with an actual class such as TControl that have a public virtual constructor that takes an argument.

constructor TControl.Create(AOwner: TComponent); override;

You still cannot specify that constructor for T.

TMyClass = class

private

  property Inner: T;

public;

  procedure InnerCreate;

end;

TMyClass.InnerCreate;

begin

   Inner := T.Create(nil); //<– [dcc32 Error] : E2029 ')' expected but 'NIL' found

end;

Why is this not valid?  The method is public, and the actual type of T has been specified.

Why can I have a local variable in a method that out-scopes a class property without a hint or warning?

Why can I have a local variable in a method that out-scopes a class property without a hint or warning?

One thing is allowing name overlaps for method parameters, but for local variables – does that even make sense?

type

  TBadClass = class

  private

    FValue: Integer;

    procedure SetValue(const Value: Integer);

  public

    procedure CheckValue;

    property Value: Integer read FValue write SetValue;

  end;

procedure TBadClass.SetValue(const Value: Integer);

begin

  FValue := Value;

end;

procedure TBadClass.CheckValue;

var

  Value: Integer;

begin

  Value := 1;

  Writeln(‘Value ‘, Value);

  Writeln(‘Self ‘, Self.Value);

  Self.Value := 2;

  Writeln(‘Value ‘, Value);

  Writeln(‘Self ‘, Self.Value);

end;

Output is

Value 1

Self 0

Value 1

Self 2

 

method Something; overload; virtual; abstract; and Deprecated

method Something; overload; virtual; abstract; and Deprecated

overload; virtual; abstract; deprecated;

deprecated; overload; virtual; abstract;

overload; deprecated; virtual; abstract;

[dcc32 Error] : E2169 Field definition not allowed after methods or properties

Fortunately, overload; virtual; deprecated; abstract; works 🙂

I am sure there is logic in there, and that someone will tell me about it 🙂

Another reason why hints can be a sign of smelly code

Another reason why hints can be a sign of smelly code

Daniela Osterhagen pointed out that hints like “var declared but not used” could be a hint of a reference mistake, and today I stumbled on another reason why hints should not be ignored.

[dcc32 Hint] somefilename.pas(666): H2077 Value assigned to ‘r’ never used

begin

  ZeroMemory(@w32fd, Sizeof(TWin32FindData));

  w32fd.dwFileAttributes := FILE_ATTRIBUTE_DIRECTORY;

  ifs := TFileSystemBindData.Create;

  ifs.SetFindData(w32fd);

  r := CreateBindCtx(0, pbc);

  r := pbc.RegisterObjectParam(STR_FILE_SYS_BIND_DATA, ifs);

end;

In this case, the hint reveals that error handling is missing for these two calls.  The actual calls in this specific snippet might not be error prone, but …

The point is: A “value never used” hint may indicate potential flow control flaws, resulting in stability or security pitfalls.