Variable is passed by reference instead of value - Why? lazarus / 21-General ---------------------------------------------------------------------- bgravity · 2022-11-08 21:26 Big picture: I am using a stringgrid for data entry. I want to highlight cells with invalid entries. I am using the solution proposed by TLama on stackoverflow here:  https://stackoverflow.com/questions/9684266/how-to-toggle-the-cell- colour-and-text-in-a-tstringgrid-on-and-off Details: In addition to highlighting errors I need to reset the cell color to default colors each time the user edits the cell so that when the user corrects the error the cell returns to the default color. I am using two variables to hold the cell colors, a form variable that holds the default values and a local procedure variable that holds the value for the current cell. I am having two issues: 1. Changes to the local variable are affecting the form variable 2. I get an access violation when I free the memory for the form variable. I have tracked the problem to the fact that when I assigned the local variable the default values, instead of copying the values from the default to the local variable, the two variables are assigned the same memory, meaning they are really just one variable not two. My questions: 1. Is there a better way to change the stringgrid cell background than the stackoverflow solution? 2. Why are acelldata and fdefaultcelldata set to the same memory location instead of copying the values from default to acelldata. If I use a record, I get the behavior I expect but I don't think I can store a record in Tstringgrid.object. 3. Is there a way to get the behavior I expect? Thanks in advance Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i unit Unit1; {$mode objfpc}{$H+} interface uses  Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls, celldata;  type  stcelldata = record    validInput:Boolean;    foregroundColor:TColor;    backgroundColor:Tcolor;  end;   { TForm1 }   TForm1 = class(TForm)    Button1: TButton;    procedure Button1Click(Sender: TObject);    procedure FormCreate(Sender: TObject);    procedure FormDestroy(Sender: TObject);  private    fdefaultCelldata:TCellData;    fstdefaultCellData:stcelldata;  public   end; var  Form1: TForm1; implementation {$R *.lfm} { TForm1 } procedure TForm1.FormCreate(Sender: TObject);begin  fdefaultCelldata:=TCellData.create(True,clBlack,clWindow);  fdefaultTime:=2;  fstdefaultCellData.backgroundColor:=clWindow;  fstdefaultCellData.foregroundColor:=clBlack;  fstdefaultCellData.validInput:=True;end; procedure TForm1.Button1Click(Sender: TObject);var  acelldata:Tcelldata;  astcelldata:stcelldata;begin  acelldata := TCellData.create(True,clBlack,clWindow);  acelldata :=fdefaultcelldata;                                          // This assigns the memory of acelldata to the same location as fdefaultcelldata  astcelldata := fstdefaultCelldata;                                // This behaves as I expect, copying the default values to astcelldata  try    acelldata.ValidInput:=false;    astcelldata.validInput:=false;  finally    acelldata.free;                                                        // This call to acelldata works  end;end; procedure TForm1.FormDestroy(Sender: TObject);begin  fdefaultCelldata.Free;                                                   // This call to free causes an access violationend;end.   unit celldata; {$mode ObjFPC}{$H+} interface uses  Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls; type TCellData=class(TObject)private  fValidInput:Boolean;  fForeground:TColor;  fBackground:TColor;public  property ValidInput:Boolean read fValidInput write fValidInput;  property ForegroundColor:TColor read fForeground write fForeground;  property BackgroundColor:TColor read fBackground write fBackground;   Constructor Create(Valid: Boolean; fg, bg:TColor);end;  implementation { TCellData } constructor TCellData.Create(Valid: Boolean; fg, bg:TColor);begin  ValidInput:=Valid;  ForegroundColor:=fg;  BackgroundColor:=bg;end; end. ---------------------------------------------------------------------- Leledumbo · 2022-11-08 21:54 Quote from: bgravity on November 08, 2022, 10:26:31 pm1. Is there a better way to change the stringgrid cell background than the stackoverflow solution? Better is subjective. I might use an external in-memory matrix instead of storing extended cell data that contains colors and such into the grid's objects property, but that's just me. Basically I try to keep actual data from rendering data for maintainability reason. Quote from: bgravity on November 08, 2022, 10:26:31 pm2. Why are acelldata and fdefaultcelldata set to the same memory location instead of copying the values from default to acelldata. If I use a record, I get the behavior I expect but I don't think I can store a record in Tstringgrid.object. TCellData is a class, therefore when you do: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i x := TCellData.Create; it creates the instance somewhere on the heap then makes x points to that instance. x holds the reference to the object, not the object itself. So when you do: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i y := x; you make y and x both point at the same object, not making y a copy of (the object) x (is pointing at). Quote from: bgravity on November 08, 2022, 10:26:31 pm3. Is there a way to get the behavior I expect? Yes, make a deep copy method in TCellData. You might remember some types, typically those that descend from TPersistent, have Assign method that accept its own type (or a TPersistent) as the sole parameter. Inside, it selectively copies the properties to make a clone. Here's how TStrings implement its Assign method.