Is using System.Assigned () a trap? What is your opinion?

emailx45

Местный
Регистрация
5 Май 2008
Сообщения
3,571
Реакции
2,438
Credits
573
Initially, please, to those who are most virtuous in the knowing:
  • Do not be offended by my question! (My brain is a mess sometimes!)
  • If you are not interested, please feel free to skip this question.
It's just a question that I would like to hear from you and, if possible, an explanation of your point of view!

My VCL in 32bits code test in RAD Studio 10.3.2 Arch - MSWindows 10 PRO build 1903 / 64bits

Код:
unit UnitMyClassX;

interface

uses
  Winapi.Windows,
  Winapi.Messages,
  System.SysUtils,
  System.Variants,
  System.Classes,
  Vcl.Graphics,
  Vcl.Controls,
  Vcl.Forms,
  Vcl.Dialogs,
  Vcl.StdCtrls;

type
  TMyClassX = class
  private
    FMyName: String;
    procedure SetMyName(const Value: String);
  public
    property MyName: String read FMyName write SetMyName;
  end;

  //
  TForm1 = class(TForm)
    Button1: TButton;
    Memo1: TMemo;
    procedure Button1Click(Sender: TObject);
  private
    procedure prcMyLog(lText:String);
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.prcMyLog(lText:String);
begin
  Memo1.Lines.Add(lText);
  Memo1.Lines.Add('');
end;


type
  TMyFunction = function: Pointer; // better to scope!

  // var
  // LMyFunction: TMyFunction = MyFunction; // dont works here! MyFunction is below!

function MyFunction: Pointer; // its ok! now!
begin
  Result := nil;
end;

// type
// TMyFunction = function: Pointer; // works too!

var
  LMyFunction: TMyFunction = MyFunction; // here is accepted! works likes Global (to down) use for this implementation!

  {
    function MyFunction: Pointer; // its not OK, because my "var" definition above!
begin
Result := nil;
end;
  }

procedure TMyClassX.SetMyName(const Value: String);
begin
  FMyName := Value;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  lMyClassX: TMyClassX;
  //
  LNotifyEvent: TNotifyEvent;
  //
  // LMyFunction: TMyFunction = MyFunction; // cannot initialize local variables!
  //
begin
  { On HELP SYSTEM:

Tests for a "nil" (unassigned) pointer or procedural variable.

Use "Assigned" to determine whether the pointer or the procedure referenced by "P is nil".
"P" must be a "variable reference of a pointer or procedural type".

"Assigned(P)" corresponds to the test "P <> nil" for a "pointer variable",
and "@P <> nil" for a "procedural variable".

"Assigned" returns False if "P is nil", True otherwise.

Tip: When testing object events and procedures for assignment,
you cannot test for "nil", and using "Assigned" is the right way.
  }
  //
  // note that my variables is not explicitly assigned!
  //
  Memo1.Clear;
  //
  if Assigned(lMyClassX) then
    prcMyLog('lMyClassX is Assigned') { <-- is returning this line, is TRUE }
  else
    prcMyLog('lMyClassX is Not Assigned');
  //
  if (lMyClassX <> nil) then
    prcMyLog('lMyClassX is Assigned') { <-- is returning this line, is TRUE }
  else
    prcMyLog('lMyClassX is Not Assigned');
  //
  // testing my NotifyEvent variable:
  //
  if Assigned(LNotifyEvent) then
    prcMyLog('lMyNotifyEvent is Assigned') { <-- is returning this line, is TRUE }
  else
    prcMyLog('lMyNotifyEvent is Not Assigned');
  //
  // --> "LNotifyEvent" dont appears on "Ctrl+Space" for choice (likes "lMyClassX")
  // --> but same forcing this expression i have this error:
  //
  // if (LNotifyEvent <> nil) then --> E2035 Not enought actual parameters ...
  // --> F2063 Could not compile used unit "UnitMyClassX.pas"
  { On Help System:

Tip: In particular cases there is a difference between using "Assigned(Something)"
and "Something <> nil".
  }
  //
  // ******************************************************************************
  {
    For instance, in the following code "Assigned(LMyFunction)" checks whether
the "LMyFunction variable" is "actually assigned",

while "LMyFunction<> nil" tests "the result value of LMyFunction for assignment".
  }

  if (LMyFunction <> nil) then
    prcMyLog('Statement "LMyFunction <> nil"')
  else
    prcMyLog('Statement "LMyFunction = nil"'); { <-- is returning this line, is FALSE }
  //
  if Assigned(LMyFunction) then
    prcMyLog('Statement "Assigned(LMyFunction)" = true') { <-- is returning this line, is TRUE }
  else
    prcMyLog('Statement "Assigned(LMyFunction)" = false');
  //
  { on Help System:

Note: "Assigned" cannot detect a dangling pointer --that is, "one that is not nil",
but that "no longer points to valid data".

For example, in the code example for "Assigned(SystemAssigned)",
Assigned does "not detect that P is not valid".
  }
  //
  // testing my "Form1" variable"
  //
  if (Form1 <> nil) then
    prcMyLog('Statement "Form1 <> nil"') { <-- is returning this line, is TRUE }
  else
    prcMyLog('Statement "Form1 = nil"');
  //
  if Assigned(Form1) then
    prcMyLog('Statement "Assigned(Form1)" = true') { <-- is returning this line, is TRUE }
  else
    prcMyLog('Statement "Assigned(Form1)" = false');
  //
  //
  if (TForm1 <> nil) then
    prcMyLog('Statement "TForm1 <> nil"') { <-- is returning this line, is TRUE }
  else
    prcMyLog('Statement "TForm1 = nil"');
  //
  (*
    if Assigned(TForm1) then // E2036 Variable required  --> on compile!
prcMyLog('Statement "Assigned(TForm1)" = true')
else
prcMyLog('Statement "Assigned(TForm1)" = false');
  *)
  //
end;

end.

System-Assigned_Function_Tests.png

hug for all