ghkweon / dwscript

Automatically exported from code.google.com/p/dwscript
0 stars 0 forks source link

Compiler thinks fields are not variables #475

Open GoogleCodeExporter opened 8 years ago

GoogleCodeExporter commented 8 years ago
procedure SetValue(var val: integer);

type
   TMyClass = class
   private
      FValue: integer;
   public
      constructor Create;
   end;

constructor TMyClass.Create;
begin
   SetValue(FValue);
end;

Expected: This should work
Observed: Syntax Error: Only a variable can be be passed as Var-parameter

Original issue reported on code.google.com by masonwhe...@gmail.com on 7 Jul 2014 at 2:53

GoogleCodeExporter commented 8 years ago
This is a current limitation due to lack of support for the capture of the 
"context".
For a class field, capture wouldn't be too complicated, but in the general 
case, it's a bit more involved (like for records, static arrays), as you would 
need to capture the context of the reference-counted entity that owns the 
record/static array.

Typically, Delphi will accept the following code, and then happily generate an 
AV/memory overwrite (even the ARC Delphi afaik), and this just isn't acceptable 
in DWScript:

   var obj : TMyClass;

   procedure FreeObj;
   begin
      obj.Free;
      obj:=nil;
   end;

   procedure TestVar(var v : Integer);
   begin
      FreeObj;
      v:=0;
   end;

   TestVar(obj.FValue);

Another consideration is that for "var" parameters to work in other 
environments with immutable basic types (like JS/Smart), the var parameters 
need to be boxed, and this would impose a significant overhead when 
reading/writing a var parameter.

Original comment by zar...@gmail.com on 7 Jul 2014 at 6:25

GoogleCodeExporter commented 8 years ago
It was actually in Smart that I ran into this bug.  I'm porting some code that 
passes an array field by reference, and I ended up having to make a local copy, 
pass it, and copy the result back.  (Talk about imposing significant overhead!)

Original comment by masonwhe...@gmail.com on 7 Jul 2014 at 1:22

GoogleCodeExporter commented 8 years ago
Element of an array in Smart is one of the problematic cases, and your overhead 
wasn't actually that bad. The solutions are all problematic:

1) using an interface/class would involve a getter/setter, would work for 
simple types or assigning records (if inefficient), but wouldn't work if you 
were to modified the fields of a record passed as var (as the original wouldn't 
be modified)

2) boxing wouldn't have the previous issue, but means that as soon as one 
function somewhere passes an element of the array's type, then that array's 
elements would need to be boxed, ie. as soon as you have somewhere a var 
parameter on an item of an "array of integer" then all "array of integer" would 
need to be codegen'ed as as "array of TBoxedInteger" with TBoxedInteger a class 
with an integer field.

So the 2nd option would have significant performance implication. Currently the 
boxing is performed for local variables, only when necessary, so the 
performance implications aren't too drastic (but usually a "var" parameter in 
Smart isn't a ticket to performance like it can be in Delphi)

Also the 2nd option wouldn't be entirely perfect either, as it would be 
possible to pass the Nth element as var, reduce the size of the array to N-2 
then increase it to N+2, but in that case var would be a boxed item detached 
from the array, and no longer the Nth element of the array.

Original comment by zar...@gmail.com on 8 Jul 2014 at 8:40