Forum > Beginners
lost pointer
tòfol:
Hello,
I'm porting a small test app from Rust to Free Pascal, but I have a problem with the 'loss' of a pointer. I have a unit called mqtt.pas with the following:
--- Code: Pascal [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---unit mqtt; interface uses classes; type TMqttMessage = class public Payload: string; Topic: string; class function GetMessage(): TMqttMessage; end; TMqttClient = class public AppMessage: ^TMqttApplicationMessage; GetData: TList; constructor Create; procedure ReceivedMessage(msg: TMqttMessage); procedure OnGetData(c:TMqttClient; e: TMqttMessage); end; TMqttApplicationMessage = class public GetData: ^TNamedDelegate; procedure ApplicationMessageReceived(client: TMqttClient; msg: TMqttMessage); end; //In case one wishes to assign methods of a class to a variable of procedural type, the procedural type must be _ //declared with the of object modifier. TNamedDelegate = procedure(client: TMqttClient; msg: TMqttMessage) of object; implementation constructor TMqttClient.Create();var tmp, tmp1: TMqttApplicationMessage; del, del1, del2: TNamedDelegate;begin Self.GetData:=TList.Create; tmp:=TMqttApplicationMessage.Create(); del:=TNamedDelegate(@Self.OnGetData); tmp.GetData:= @del; del1:=tmp.GetData^; Self.AppMessage:=@tmp; tmp1:=Self.AppMessage^; del2:=tmp1.GetData^;end; procedure TMqttClient.OnGetData(c:TMqttClient; e: TMqttMessage);var n: ^TNamedDelegate;begin for n in Self.GetData do n^(c, e); end; procedure TMqttClient.ReceivedMessage(msg: TMqttMessage);var appMsg: TMqttApplicationMessage; del: TNamedDelegate;begin appMsg:=Self.AppMessage^; del:=appMsg.GetData^; appMsg.ApplicationMessageReceived(Self, msg);end; class function TMqttMessage.GetMessage(): TMqttMessage;begin result:=TMqttMessage.Create; result.Payload:='A Payload'; result.Topic:='A Topic';end; procedure TMqttApplicationMessage.ApplicationMessageReceived(client: TMqttClient; msg: TMqttMessage);var del: TNamedDelegate;begin del:=Self.GetData^; del(client, msg);end; end.
And I call this code from hello.pas:
--- Code: Pascal [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---program Hello;{$TYPEDADDRESS ON} uses mqtt; var MqttClient: TMqttClient; Msg: TMqttMessage; procedure GetData(client: TMqttClient; msg: TMqttMessage);begin writeln ('Message Payload on Data: ' + msg.Payload + ' Topic: ' + msg.Topic);end; procedure GetData1(client: TMqttClient; msg: TMqttMessage);begin writeln ('Message Payload on Data1: ' + msg.Payload + ' Topic: ' + msg.Topic);end; begin MqttClient:=TMqttClient.Create(); Msg:=TMqttMessage.GetMessage(); MqttClient.GetData.Add(@GetData); MqttClient.GetData.Add(@GetData1); MqttClient.ReceivedMessage(Msg); ReadLn;end.
I'm running
--- Quote ---Free Pascal Compiler version 3.2.2 [2022/07/21] for x86_64
--- End quote ---
The problem I have is on line 65 of mqtt.pas:
--- Code: Pascal [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---del:=appMsg.GetData^;Where I obtain an access violation. What's strange to me is that this pointer is okay when I test it in the constructor of TMqttClient, but when I attempt to access it from hello.pas here:
--- Code: Pascal [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---MqttClient.ReceivedMessage(Msg);
I get the problem. Any pointers to help me understand this issue would be greatly appreciated :)
PascalDragon:
--- Quote from: tòfol on March 17, 2023, 12:57:38 pm ---Any pointers to help me understand this issue would be greatly appreciated :)
--- End quote ---
First of get rid of the pointers for TMqttClient.TMqttApplicationMessage and TMqttApplicationMessage.GetData. Object Pascal style classes already are pointers and function/method variables are pointer types as well.
Then best use a generic list for TMqttClient.GetData (and I personally wouldn't name that field GetData, cause with the Get prefix I'd assume it to be a method). For example by using unit Generics.Collections and using specialize TList<TNamedDelegate> instead of TList (you'll also have to move the declaration of TNamedDelegate further up - after the declaration of TMqttMessage - and add a forward declaration for TMqttClient before TNamedDelegate (TMqttClient = class;)).
Then inside your TMqttClient.Create you don't need to use TNamedDelegate(@Self.OnGetData). @Self.OnGetData or even @OnGetData is enough (also I wouldn't name that method OnGetData, cause the On prefix is usually used for event properties (properties of type method pointer). And you don't need to use the dereferentiation operator as well nor the @tmp or @del.
So first clean this up, post the cleaned up code and then we can check what is really going on if that doesn't already fix your issues.
Blaazen:
Yes, replace
--- Code: Pascal [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---AppMessage: ^TMqttApplicationMessage;with just
--- Code: Pascal [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---AppMessage: TMqttApplicationMessage;And then you will need forward declalaration.
I noticed another issue: you mix methods and procedures.
--- Code: Pascal [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---TNamedDelegate = procedure(client: TMqttClient; msg: TMqttMessage) of object;is method (size 16 bytes) and you feed it to TList which holds just pointers (8 bytes).
This procedure from hello.lpr:
--- Code: Pascal [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---procedure GetData(client: TMqttClient; msg: TMqttMessage);begin writeln ('Message Payload on Data: ' + msg.Payload + ' Topic: ' + msg.Topic);end;is not type TNamedDelegate, since it is not a method.
tòfol:
Thank you very much @PascalDragon and @Blaazen for your replies.
The forward declaration of class has been very helpful. However, I still don't fully understand what's happening with the procedural type. My mqtt.pas compiles, and looks like this:
--- Code: Pascal [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---unit mqtt; interface uses Classes, Generics.Collections; type TMqttClient = class; TMqttMessage = class; TMqttApplicationMessage = class; //In case one wishes to assign methods of a class to a variable of procedural type, the procedural type must be _ //declared with the of object modifier. TNamedDelegate = procedure(client: TMqttClient; msg: TMqttMessage) of object; TMqttMessage = class public Payload: string; Topic: string; class function GetMessage(): TMqttMessage; end; TMqttClient = class public AppMessage: TMqttApplicationMessage; Data: array of TNamedDelegate; //Data: TList<TNamedDelegate>; constructor Create; procedure ReceivedMessage(msg: TMqttMessage); procedure GetData(c:TMqttClient; e: TMqttMessage); end; TMqttApplicationMessage = class public Data: TNamedDelegate; constructor Create(func: TNamedDelegate); procedure ApplicationMessageReceived(client: TMqttClient; msg: TMqttMessage); end; implementation constructor TMqttClient.Create();begin SetLength(Data, 2); Self.AppMessage:=TMqttApplicationMessage.Create(@GetData);end; procedure TMqttClient.GetData(c:TMqttClient; e: TMqttMessage);var n: TNamedDelegate;begin for n in Self.Data do n(c, e); end; procedure TMqttClient.ReceivedMessage(msg: TMqttMessage);begin AppMessage.ApplicationMessageReceived(Self, msg);end; class function TMqttMessage.GetMessage(): TMqttMessage;begin result:=TMqttMessage.Create; result.Payload:='A Payload'; result.Topic:='A Topic';end; constructor TMqttApplicationMessage.Create(func: TNamedDelegate);begin Data:=func;end; procedure TMqttApplicationMessage.ApplicationMessageReceived(client: TMqttClient; msg: TMqttMessage);var del: TNamedDelegate;begin Data(client, msg);end; end.
For some reason I can't use the TList<T>, I'm told (but this is an incidental issue):
--- Code: Pascal [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---Syntax error, ";" expected but "<" found
I note here that if I remove of object from TNamedDelegate I get a compilation error:
--- Code: Pascal [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---Incompatible type for arg no. 1: Got "<procedure variable type of procedure(TMqttClient;TMqttMessage) of object;Register>", expected "<procedure variable type of procedure(TMqttClient;TMqttMessage);Register>"Which points to this line in the TMqttClient constructor:
--- Code: Pascal [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---Self.AppMessage:=TMqttApplicationMessage.Create(@GetData);
With mqtt.pas compiling, I now try the following in hello.pas:
--- Code: Pascal [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---{$MODE objfpc}{$H+}{$TYPEDADDRESS ON} program Hello; uses mqtt; var MqttClient: TMqttClient; Msg: TMqttMessage; procedure GetData(client: TMqttClient; msg: TMqttMessage);begin writeln ('Message Payload on Data: ' + msg.Payload + ' Topic: ' + msg.Topic);end; procedure GetData1(client: TMqttClient; msg: TMqttMessage);begin writeln ('Message Payload on Data1: ' + msg.Payload + ' Topic: ' + msg.Topic);end; begin MqttClient:=TMqttClient.Create(); Msg:=TMqttMessage.GetMessage(); MqttClient.Data[0]:= @GetData; //MqttClient.Data[1]:= TNamedDelegate(@GetData1); //MqttClient.ReceivedMessage(Msg); //ReadLn;end.
But this gives me:
--- Code: Pascal [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---Incompatible types: got "<address of procedure(TMqttClient;TMqttMessage);Register>" expected "<procedure variable type of procedure(TMqttClient;TMqttMessage) of object;Register>"
There's something I'm missing here clearly in the semantics of the procedural type. Thanks again.
Blaazen:
unit mqtt
--- Code: Pascal [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---unit mqtt; interface uses Classes, FGL; type TMqttClient = class; TMqttMessage = class; TMqttApplicationMessage = class; //In case one wishes to assign methods of a class to a variable of procedural type, the procedural type must be _ //declared with the of object modifier. TNamedDelegate = procedure(client: TMqttClient; msg: TMqttMessage); TNamedDelegateMethod = procedure(client: TMqttClient; msg: TMqttMessage) of object; TMqttMessage = class public Payload: string; Topic: string; class function GetMessage(): TMqttMessage; end; TGList = specialize TFPGList<TNamedDelegate>; { TMqttClient } TMqttClient = class public AppMessage: TMqttApplicationMessage; //Data: array of TNamedDelegate; Data: TGList; constructor Create; destructor Destroy; override; procedure ReceivedMessage(msg: TMqttMessage); procedure GetData(c:TMqttClient; e: TMqttMessage); end; TMqttApplicationMessage = class public Data: TNamedDelegateMethod; constructor Create(func: TNamedDelegateMethod); procedure ApplicationMessageReceived(client: TMqttClient; msg: TMqttMessage); end; implementation constructor TMqttClient.Create();begin Data:=TGList.Create; //SetLength(Data, 2); Self.AppMessage:=TMqttApplicationMessage.Create(@GetData);end; destructor TMqttClient.Destroy;begin AppMessage.Free; Data.Free; inherited Destroy;end; procedure TMqttClient.GetData(c:TMqttClient; e: TMqttMessage);var n: TNamedDelegate;begin for n in Self.Data do n(c, e);end; procedure TMqttClient.ReceivedMessage(msg: TMqttMessage);begin AppMessage.ApplicationMessageReceived(Self, msg);end; class function TMqttMessage.GetMessage(): TMqttMessage;begin result:=TMqttMessage.Create; result.Payload:='A Payload'; result.Topic:='A Topic';end; constructor TMqttApplicationMessage.Create(func: TNamedDelegateMethod);begin Data:=func;end; procedure TMqttApplicationMessage.ApplicationMessageReceived(client: TMqttClient; msg: TMqttMessage);var del: TNamedDelegate;begin Data(client, msg);end; end.
program
--- Code: Pascal [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---{$MODE objfpc}{$H+}{$TYPEDADDRESS ON} program Hello; uses mqtt; var MqttClient: TMqttClient; Msg: TMqttMessage; procedure GetData(client: TMqttClient; msg: TMqttMessage);begin writeln ('Message Payload on Data: ' + msg.Payload + ' Topic: ' + msg.Topic);end; procedure GetData1(client: TMqttClient; msg: TMqttMessage);begin writeln ('Message Payload on Data1: ' + msg.Payload + ' Topic: ' + msg.Topic);end; begin MqttClient:=TMqttClient.Create(); Msg:=TMqttMessage.GetMessage(); MqttClient.Data.Add(@GetData); MqttClient.Data.Add(@GetData1); MqttClient.ReceivedMessage(Msg); MqttClient.Free; Msg.Free; ReadLn;end.
I used FGL for list and I separated TNamedDelegate and TNamedDelegateMethod.
Navigation
[0] Message Index
[#] Next page