Recent

Author Topic: Reference to parameter even if not 'var' or 'out' used  (Read 285 times)

rnfpc

  • Jr. Member
  • **
  • Posts: 91
Reference to parameter even if not 'var' or 'out' used
« on: July 11, 2019, 11:24:46 am »
I am trying following code to modify sent argument parameter in the procedure:

Code: Pascal  [Select]
  1. {$mode objfpc}
  2. uses classes;
  3. procedure myproc(slist: Tstringlist); // NO var OR out KEYWORD USED HERE;
  4. begin
  5.         slist.clear;
  6.         slist.add('one');
  7.         slist.add('two');
  8. end;  
  9.  
  10. var
  11.         tsl: Tstringlist;
  12. begin
  13.         tsl:= Tstringlist.create;
  14.         myproc(tsl);
  15.         writeln(tsl.text);
  16. end.
Output:
Code: Pascal  [Select]
  1. one
  2. two


I find that above code works even when no 'var' or 'out' keywords are used in procedure myproc header. When are 'out' and 'var' keywords to be used?

PascalDragon

  • Hero Member
  • *****
  • Posts: 636
  • Compiler Developer
Re: Reference to parameter even if not 'var' or 'out' used
« Reply #1 on: July 11, 2019, 11:29:31 am »
Class instance variables are implicitely pointers to the real class instance, so if you work on the instance you don't need var or out. However if you want to modify the instance variable you need to use them:
Code: Pascal  [Select]
  1. procedure myproc(out slist: TStringList);
  2. begin
  3.   slist := TStringList.Create;
  4.   // fill slist
  5. end;
  6.  
  7. var
  8.   sl: TStringList;
  9. begin
  10.   myproc(sl);
  11.   sl.Free;
  12. end.
  13.  
Also you need to use those parameter notifiers when you want to modify primitive (e.g. Integer, String) or record types.

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 5635
    • wiki
Re: Reference to parameter even if not 'var' or 'out' used
« Reply #2 on: July 11, 2019, 01:13:04 pm »
In case of an object (class instance), it is the instance (reference in the variable) that is affected by "var". Not the data in the instance.

There is only one instance. So the data in the instance (as you found out) is always the same.

Code: Pascal  [Select]
  1.     var   a, b: Tstringlist;
  2.  

Now you have 2 variables. They can both point to the same instance, or they can have different instances
Code: Pascal  [Select]
  1.     var   a, b: Tstringlist;
  2.     begin
  3.             a:= Tstringlist.create;
  4.             b:= a;  // only one instance // 2 vars refering to it
  5.             b.add('foo');
  6.             writeln(tsl.text);
  7.             freeAndNil(a);
  8.             // b in NOT nil. But it is NO LONGER VALID, the data it points to is gone
  9.     end.

Code: Pascal  [Select]
  1.     {$mode objfpc}
  2.     uses classes;
  3.     procedure myproc(var slist: Tstringlist); // NO var OR out KEYWORD USED HERE;
  4.     begin
  5.             freeandnil(slist);
  6.     end;  
  7.      
  8.     var
  9.             tsl: Tstringlist;
  10.     begin
  11.             tsl:= Tstringlist.create;
  12.             myproc(tsl);
  13.            // tsl is nil
  14.     end.
Without the var param, tsl would NOT be nil. Yet tsl would be invalid.

Code: Pascal  [Select]
  1.     {$mode objfpc}
  2.     uses classes;
  3.     procedure myproc(var slist: Tstringlist); // NO var OR out KEYWORD USED HERE;
  4.     begin
  5.             slist := TMySubclassedStringList.create.
  6.     end;  
  7.      
  8.     var
  9.             tsl: Tstringlist;
  10.     begin
  11.             tsl:= Tstringlist.create;
  12.             myproc(tsl);
  13.            // tsl is TMySubclassedStringList
  14.     end.
without the var, tsl would still be a valid stringlist.
In this case you did not free the stringlist (may lead to a leak). So without "var" tsl stays valid, as the stringlist's data still exists.

rnfpc

  • Jr. Member
  • **
  • Posts: 91
Re: Reference to parameter even if not 'var' or 'out' used
« Reply #3 on: July 11, 2019, 03:58:45 pm »
Thanks @PascalDragon and @Martin_fr for clarifying the issue.