Recent

Author Topic: NIL vs. Assign: when to use - or: what are the differences ?  (Read 4876 times)

paule32

  • Sr. Member
  • ****
  • Posts: 401
NIL vs. Assign: when to use - or: what are the differences ?
« on: March 15, 2025, 12:51:51 pm »
Hello,

on some Code places I saw the use of:

Code: Pascal  [Select][+][-]
  1. if foo <> nil then
  2. ...

on others, I saw:

Code: Pascal  [Select][+][-]
  1. if Assigned(foo) then
  2. ...

so, what are the Differences between nil and Assigned ?
And: when       to use
And: when not to use
?
« Last Edit: March 15, 2025, 12:54:10 pm by paule32 »
MS-IIS - Internet Information Server, Apache, PHP/HTML/CSS, MinGW-32/64 MSys2 GNU C/C++ 13 (-stdc++20), FPC 3.2.2
A Friend in need, is a Friend indeed.

cdbc

  • Hero Member
  • *****
  • Posts: 2095
    • http://www.cdbc.dk
Re: NIL vs. Assign: when to use - or: what are the differences ?
« Reply #1 on: March 15, 2025, 12:59:42 pm »
Hi
Your first example is exactly what Assigned() does, i.e.: checks if a pointer is NIL or not...
Afaik the 2 uses are interchangeable... => no difference.
Regards Benny
If it ain't broke, don't fix it ;)
PCLinuxOS(rolling release) 64bit -> KDE5 -> FPC 3.2.2 -> Lazarus 3.6 up until Jan 2024 from then on it's both above &: KDE5/QT5 -> FPC 3.3.1 -> Lazarus 4.99

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 11027
  • Debugger - SynEdit - and more
    • wiki
Re: NIL vs. Assign: when to use - or: what are the differences ?
« Reply #2 on: March 15, 2025, 01:29:22 pm »
Hi
Your first example is exactly what Assigned() does, i.e.: checks if a pointer is NIL or not...
Afaik the 2 uses are interchangeable... => no difference.
Regards Benny

Afaik there is a diff, at least for method pointers (pointer to proc or func of object).

Those pointers have a value for code and self. Assigned checks both and <>nil only one (or the other way round)?

But if it ever makes a diff would then depend if your code ever has data that has such a case. And you may want one or the other in different scenarios.

dseligo

  • Hero Member
  • *****
  • Posts: 1500
Re: NIL vs. Assign: when to use - or: what are the differences ?
« Reply #3 on: March 15, 2025, 01:40:35 pm »
Hi
Your first example is exactly what Assigned() does, i.e.: checks if a pointer is NIL or not...
Afaik the 2 uses are interchangeable... => no difference.
Regards Benny

Afaik there is a diff, at least for method pointers (pointer to proc or func of object).

Yes. From docs (https://www.freepascal.org/docs-html/rtl/system/assigned.html):
Quote
The main use of Assigned is that Procedural variables, method variables and class-type variables also can be passed to Assigned.

cdbc

  • Hero Member
  • *****
  • Posts: 2095
    • http://www.cdbc.dk
Re: NIL vs. Assign: when to use - or: what are the differences ?
« Reply #4 on: March 15, 2025, 01:50:11 pm »
Hi
You guys just jogged my memory, I remember reading*) @PascalDragon saying something about 'Assigned' will call said func/proc/method pointer to check its validity and that, in those situations where you don't want that, you should use 'x <> NIL' instead.
*)Read a couple of years ago or more...
Regards Benny
If it ain't broke, don't fix it ;)
PCLinuxOS(rolling release) 64bit -> KDE5 -> FPC 3.2.2 -> Lazarus 3.6 up until Jan 2024 from then on it's both above &: KDE5/QT5 -> FPC 3.3.1 -> Lazarus 4.99

MarkMLl

  • Hero Member
  • *****
  • Posts: 8364
Re: NIL vs. Assign: when to use - or: what are the differences ?
« Reply #5 on: March 15, 2025, 02:13:34 pm »
You guys just jogged my memory, I remember reading*) @PascalDragon saying something about 'Assigned' will call said func/proc/method pointer to check its validity and that, in those situations where you don't want that, you should use 'x <> NIL' instead.
*)Read a couple of years ago or more...

Yes, I remember either that or a similar discussion.

So it's really another example of where Pascal's omission of parentheses on a function being called causes problems.

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Logitech, TopSpeed & FTL Modula-2 on bare metal (Z80, '286 protected mode).
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

BrunoK

  • Hero Member
  • *****
  • Posts: 696
  • Retired programmer
Re: NIL vs. Assign: when to use - or: what are the differences ?
« Reply #6 on: March 15, 2025, 02:57:19 pm »
The code in the program below results strictly in the same assembly code for testing Assigned(vProc) or vProc<>nil.
Can someone show an example where the code would be different please.
Code: Pascal  [Select][+][-]
  1. program Project1;
  2.   procedure CalledByPointer;
  3.   begin
  4.  
  5.   end;
  6.  
  7. var
  8.   vProc: procedure;
  9.  
  10. begin
  11.   if Assigned(vProc) then
  12.     WriteLn('Assigned(vProc)');
  13.   if vProc<>nil then
  14.     WriteLn('vProc<>nil');
  15.  
  16.   vProc := @CalledByPointer;
  17.   if Assigned(vProc) then
  18.     WriteLn('after vProc := @... Assigned(vProc)');
  19.   if vProc<>nil then
  20.     WriteLn('after vProc := @... vProc<>nil');
  21.  
  22.   ReadLn;
  23. end.



Paolo

  • Hero Member
  • *****
  • Posts: 581
Re: NIL vs. Assign: when to use - or: what are the differences ?
« Reply #7 on: March 15, 2025, 06:13:36 pm »
@BrunoK, what mode ? objfpc or delphi ?

can you try with delphi mode ?


440bx

  • Hero Member
  • *****
  • Posts: 5162
Re: NIL vs. Assign: when to use - or: what are the differences ?
« Reply #8 on: March 15, 2025, 07:24:26 pm »
the call through variables mechanism is rather confusing to say the least.

Consider the following code (modified from BrunoK's):
Code: Pascal  [Select][+][-]
  1. {$MODE OBJFPC}
  2.  
  3. program Project1;
  4.   procedure ProcCalledByPointer;
  5.   begin
  6.     writeln('proc CalledByPointer was executed');
  7.   end;
  8.  
  9.   function  FuncCalledByPointer : boolean;
  10.   begin
  11.     result := TRUE;
  12.     writeln('func - 1 - CalledByPointer was executed');
  13.   end;
  14.  
  15.   function  FuncCalledByPointer(p : integer) : pointer;
  16.   begin
  17.     result := nil;
  18.     inc(p);
  19.     writeln('func - 2 - CalledByPointer was executed');
  20.   end;
  21.  
  22.  
  23.  
  24. var
  25.   vProc  : procedure;
  26.   vFunc  : function()            : boolean;
  27.   vFunc2 : function(p : integer) : pointer;
  28.  
  29. begin
  30.   if Assigned(vProc) then
  31.     WriteLn('Assigned(vProc)');
  32.   if vProc<>nil then
  33.     WriteLn('vProc<>nil');
  34.  
  35.   vProc := @ProcCalledByPointer;
  36.   if Assigned(vProc) then
  37.     WriteLn('after vProc := @... Assigned(vProc)');
  38.  
  39.   if vProc <> nil then
  40.     WriteLn('after vProc := @... vProc<>nil');
  41.  
  42.   vproc;
  43.  
  44.   { ------------------------------------------------------------------------- }
  45.  
  46.   { now with a function                                                       }
  47.  
  48.   if Assigned(vFunc) then
  49.     WriteLn('Assigned(vFunc)');
  50.   if vFunc<>nil then
  51.     WriteLn('vFunc<>nil');
  52.  
  53.   vFunc := @FuncCalledByPointer;
  54.   if Assigned(vFunc) then
  55.     WriteLn('after vFunc := @... Assigned(vFunc)');
  56.  
  57.   { parentheses make a difference, i.e, vFunc <> vFunc()                      }
  58.  
  59.   if vFunc <> nil then
  60.     WriteLn('after vFunc := @... vFunc<>nil');
  61.  
  62.   vFunc; { parentheses DON'T make a difference here, i.e, vFunc = vFunc()     }
  63.  
  64.   { ------------------------------------------------------------------------- }
  65.  
  66.   { now with a function that takes parameters                                 }
  67.  
  68.   if Assigned(vFunc2) then
  69.     WriteLn('Assigned(vFunc2)');
  70.   if vFunc2<>nil then
  71.     WriteLn('vFunc2<>nil');
  72.  
  73.   vFunc2 := @FuncCalledByPointer;
  74.   if Assigned(vFunc2) then
  75.     WriteLn('after vFunc2 := @... Assigned(vFunc2)');
  76.  
  77.   if vFunc2 <> nil then
  78.     WriteLn('after vFunc2 := @... vFunc2<>nil');
  79.  
  80.   if vFunc2(1) <> nil then
  81.     WriteLn('after vFunc2 := @... vFunc2<>nil');
  82.  
  83.   vFunc2(1);
  84.  
  85.   writeln;
  86.   writeln('press ENTER/RETURN to end this program');
  87.   ReadLn;
  88. end.                              
  89.  
The difference between the highlighted lines is subtle enough that it would be reasonable for a programmer to not know why in one case the vFunc target is not called yet it is called in the other case that looks (but isn't) identical.

As MarkMLI pointed out, Pascal's not requiring the parentheses to indicate a call is being made is a flaw in the language.  One that can bite even an experienced programmer.

Suggestion: _always_ put the parentheses, that way when the parentheses are missing, whoever is reading the code may suspect there is something different going on there.

It would be very nice if FPC had some modeswitch that made the parentheses required for a function or procedure to be called, i.e, no parentheses = it's a variable reference, not a call.

ETA:

corrected a typo.
« Last Edit: March 15, 2025, 07:28:02 pm by 440bx »
(FPC v3.0.4 and Lazarus 1.8.2) or (FPC v3.2.2 and Lazarus v3.2) on Windows 7 SP1 64bit.

paule32

  • Sr. Member
  • ****
  • Posts: 401
Re: NIL vs. Assign: when to use - or: what are the differences ?
« Reply #9 on: March 15, 2025, 08:30:26 pm »
delphi mode is not possible on my side.
there is the cuted assembly with line numbers:

Code: ASM  [Select][+][-]
  1. .section .text.n_p$project1_$$_calledbypointer,"x"
  2.         .balign 16,0x90
  3. .globl  P$PROJECT1_$$_CALLEDBYPOINTER
  4. P$PROJECT1_$$_CALLEDBYPOINTER:
  5. .Lc1:
  6. # [test.pas]
  7. # [3] begin
  8. # [5] end;
  9.         ret
  10. .Lc2:
  11.  
  12. .section .text.n_main,"x"
  13.         .balign 16,0x90
  14. .globl  PASCALMAIN
  15. PASCALMAIN:
  16. .globl  main
  17. main:
  18. .Lc3:
  19. .seh_proc main
  20. # [10] begin
  21.         pushq   %rbx
  22. .seh_pushreg %rbx
  23.         pushq   %rsi
  24. .seh_pushreg %rsi
  25.         leaq    -40(%rsp),%rsp
  26. .Lc5:
  27. .seh_stackalloc 40
  28. .seh_endprologue
  29. # Var vProc located in register rsi
  30.         call    fpc_initializeunits
  31.         movq    $0,%rsi
  32. # [11] if Assigned(vProc) then
  33.         testq   %rsi,%rsi
  34.         je      .Lj6
  35. # [12] WriteLn('Assigned(vProc)');
  36.         call    fpc_get_output
  37.         movq    %rax,%rbx
  38.         leaq    _$PROJECT1$_Ld1(%rip),%r8
  39.         movq    %rbx,%rdx
  40.         xorl    %ecx,%ecx
  41.         call    fpc_write_text_shortstr
  42.         call    fpc_iocheck
  43.         movq    %rbx,%rcx
  44.         call    fpc_writeln_end
  45.         call    fpc_iocheck
  46.         .balign 4,0x90
  47. .Lj6:
  48. # [13] if vProc<>nil then
  49.         testq   %rsi,%rsi
  50.         je      .Lj8
  51. # [14] WriteLn('vProc<>nil');
  52.         call    fpc_get_output
  53.         movq    %rax,%rbx
  54.         leaq    _$PROJECT1$_Ld2(%rip),%r8
  55.         movq    %rbx,%rdx
  56.         xorl    %ecx,%ecx
  57.         call    fpc_write_text_shortstr
  58.         call    fpc_iocheck
  59.         movq    %rbx,%rcx
  60.         call    fpc_writeln_end
  61.         call    fpc_iocheck
  62.         .balign 4,0x90
  63. .Lj8:
  64. # [16] vProc := @CalledByPointer;
  65.         leaq    P$PROJECT1_$$_CALLEDBYPOINTER(%rip),%rbx
  66. # Var vProc located in register rbx
  67. # [17] if Assigned(vProc) then
  68.         testq   %rbx,%rbx
  69.         je      .Lj10
  70. # [18] WriteLn('after vProc := @... Assigned(vProc)');
  71.         call    fpc_get_output
  72.         movq    %rax,%rsi
  73.         leaq    _$PROJECT1$_Ld3(%rip),%r8
  74.         movq    %rsi,%rdx
  75.         xorl    %ecx,%ecx
  76.         call    fpc_write_text_shortstr
  77.         call    fpc_iocheck
  78.         movq    %rsi,%rcx
  79.         call    fpc_writeln_end
  80.         call    fpc_iocheck
  81.         .balign 4,0x90
  82. .Lj10:
  83. # [19] if vProc<>nil then
  84.         testq   %rbx,%rbx
  85.         je      .Lj12
  86. # [20] WriteLn('after vProc := @... vProc<>nil');
  87.         call    fpc_get_output
  88.         movq    %rax,%rbx
  89.         leaq    _$PROJECT1$_Ld4(%rip),%r8
  90.         movq    %rbx,%rdx
  91.         xorl    %ecx,%ecx
  92.         call    fpc_write_text_shortstr
  93.         call    fpc_iocheck
  94.         movq    %rbx,%rcx
  95.         call    fpc_writeln_end
  96.         call    fpc_iocheck
  97.         .balign 4,0x90
  98. .Lj12:
  99. # [22] ReadLn;
  100.         call    fpc_get_input
  101.         movq    %rax,%rcx
  102.         call    fpc_readln_end
  103.         call    fpc_iocheck
  104. # [23] end.
  105.         call    fpc_do_exit
  106.         nop
  107.         leaq    40(%rsp),%rsp
  108.         popq    %rsi
  109.         popq    %rbx
  110.         ret
  111. .seh_endproc
  112.  
MS-IIS - Internet Information Server, Apache, PHP/HTML/CSS, MinGW-32/64 MSys2 GNU C/C++ 13 (-stdc++20), FPC 3.2.2
A Friend in need, is a Friend indeed.

Remy Lebeau

  • Hero Member
  • *****
  • Posts: 1501
    • Lebeau Software
Re: NIL vs. Assign: when to use - or: what are the differences ?
« Reply #10 on: March 15, 2025, 09:48:31 pm »
In the context of Delphi, Allen Bauer once wrote a detailed blog article about what Assigned() is and why it needed to be introduced. I'm sure the same rationale applies to FreePascal, too:

Assigned or not Assigned, that is the question...
Remy Lebeau
Lebeau Software - Owner, Developer
Internet Direct (Indy) - Admin, Developer (Support forum)

Warfley

  • Hero Member
  • *****
  • Posts: 1872
Re: NIL vs. Assign: when to use - or: what are the differences ?
« Reply #11 on: March 16, 2025, 12:44:07 pm »
There is a very simple difference, Assigned never calls function pointers in mode Delphi:
Code: Pascal  [Select][+][-]
  1. {$Mode Delphi}
  2.  
  3. function Foo: Pointer;
  4. begin
  5.   Result := nil;
  6. end;
  7.  
  8. type
  9.   TPtrFunc = function: Pointer;
  10.  
  11. var
  12.   p: TPtrFunc;
  13. begin
  14.   p:=Foo;
  15.   WriteLn('<>: ', p <> nil); // False
  16.   WriteLn('Assigned: ', Assigned(p)); // True
  17. end.

Note that in Mode ObjFPC both return True

Zoran

  • Hero Member
  • *****
  • Posts: 1941
    • http://wiki.lazarus.freepascal.org/User:Zoran
Re: NIL vs. Assign: when to use - or: what are the differences ?
« Reply #12 on: March 16, 2025, 07:09:40 pm »

Warfley, thank you for simple and clear explanation (much easier to understand than Allen Bauer's explanation).

Just a small correcton:

Assigned never calls function pointers in mode Delphi:

I think you actually ment to say Assigned never calls function pointers in mode ObjFpc, right?

According to the example given in mode Delphi, as well as the note that ObjFpc always returns True:
WriteLn('<>: ', p <> nil); // False in mode Delphi -- the function pointed to by the pointer was called and returned False
WriteLn('<>: ', p <> nil); // True in mode ObjFpc -- the function pointed to was not called and True was returned just because the function pointer itself is assigned

Swan, ZX Spectrum emulator https://github.com/zoran-vucenovic/swan

PascalDragon

  • Hero Member
  • *****
  • Posts: 5938
  • Compiler Developer
Re: NIL vs. Assign: when to use - or: what are the differences ?
« Reply #13 on: March 18, 2025, 08:47:10 pm »
Consider the following code (modified from BrunoK's):

{ snip }

It would be very nice if FPC had some modeswitch that made the parentheses required for a function or procedure to be called, i.e, no parentheses = it's a variable reference, not a call.

In my opinion both vFunc; and vProc; should not compile in mode ObjFPC (or FPC), cause there the point is that brackets should be used when calling parameter-less functions. 🤔

440bx

  • Hero Member
  • *****
  • Posts: 5162
Re: NIL vs. Assign: when to use - or: what are the differences ?
« Reply #14 on: March 18, 2025, 09:02:05 pm »
In my opinion both vFunc; and vProc; should not compile in mode ObjFPC (or FPC), cause there the point is that brackets should be used when calling parameter-less functions. 🤔
I just want to reinforce that we are in complete agreement as far as to when parentheses should be used/required.
(FPC v3.0.4 and Lazarus 1.8.2) or (FPC v3.2.2 and Lazarus v3.2) on Windows 7 SP1 64bit.

 

TinyPortal © 2005-2018