<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
</head>
<body smarttemplateinserted="true">
<div id="smartTemplate4-template">Hi,<br>
<br>
<p>
<blockquote type="cite"><br>
(1) A record is not a pointer. So that would require some
implicit referencing in the property
<br>
<br>
(2) If it was managed, it would be an allocation, so I don't
understand this.
<br>
</blockquote>
</p>
<p><br>
</p>
<p>I am talking about replacing interfaces with an record.</p>
<p>For example this</p>
<p>/////////////////////////////////////</p>
<p>type ITest = interface<br>
procedure println;<br>
end;<br>
TTest = class(TInterfacedObject, ITest)<br>
v: integer;<br>
constructor Create(av: integer);<br>
procedure println;<br>
end;<br>
<br>
constructor TTest.Create(av: integer);<br>
begin<br>
v := av;<br>
end;<br>
<br>
procedure TTest.println;<br>
begin<br>
writeln(v);<br>
end;<br>
</p>
<p>var c: ITest;<br>
begin<br>
c := TTest.Create(123);<br>
c.println;<br>
/////////////////////////////////</p>
<p><br>
</p>
<p>would become:</p>
<p><br>
</p>
<p>/////////////////////////////////</p>
type<br>
<p>TTestRec = class<br>
rc: Integer;<br>
v: integer;<br>
constructor Create(av: integer);<br>
procedure println;<br>
end;<br>
RTest = record<br>
ptr: TTestRec;<br>
procedure println; inline;<br>
class operator :=(c: TTestRec): RTest;<br>
class operator Initialize(var aRec: RTest);<br>
class operator finalize(var aRec: RTest);<br>
class operator AddRef(var aRec: RTest);<br>
end;<br>
<br>
constructor TTestRec.Create(av: integer);<br>
begin<br>
v := av;<br>
end;<br>
<br>
procedure TTestRec.println;<br>
begin<br>
writeln(v);<br>
end;<br>
<br>
procedure RTest.println;<br>
begin<br>
ptr.println; //the wrapper function is inlined<br>
end;<br>
<br>
class operator RTest.:=(c: TTestRec): RTest;<br>
begin<br>
result := default(RTest);<br>
result.ptr := c;<br>
if c <> nil then<br>
InterlockedIncrement(c.rc);<br>
end;<br>
<br>
class operator RTest.Initialize(var aRec: RTest);<br>
begin<br>
aRec.ptr := nil;<br>
end;<br>
<br>
class operator RTest.finalize(var aRec: RTest);<br>
begin<br>
if aRec.ptr <> nil then<br>
if InterlockedDecrement(aRec.ptr.rc) = 0 then<br>
aRec.ptr.Free;<br>
end;<br>
<br>
class operator RTest.AddRef(var aRec: RTest);<br>
begin<br>
if aRec.ptr <> nil then<br>
InterlockedIncrement(aRec.ptr.rc);<br>
end;</p>
<p>var<br>
r: RTest;<br>
begin<br>
r := TTestRec.Create(123);<br>
r.println;<br>
/////////////////////////////////////////////////////////<br>
</p>
</div>
<div>Or even replace the class with a record, too:</div>
<div><br>
</div>
<div><br>
</div>
<div>
<p>/////////////////////////////////////////////////////////<br>
</p>
type<br>
PTestRec2 = ^TTestRec2;<br>
TTestRec2 = record<br>
rc: Integer;<br>
v: integer;<br>
class function Create(av: integer): PTestRec2; static;<br>
procedure println;<br>
end;<br>
RTest2 = record<br>
ptr: ^TTestRec2;<br>
procedure println; inline;<br>
class operator :=(c: PTestRec2): RTest2;<br>
class operator Initialize(var aRec: RTest2);<br>
class operator finalize(var aRec: RTest2);<br>
class operator AddRef(var aRec: RTest2);<br>
end;<br>
<br>
class function TTestRec2.Create(av: integer): PTestRec2;<br>
begin<br>
new(result);<br>
result^.rc := 0;<br>
result^.v := av;<br>
end;<br>
<br>
procedure TTestRec2.println;<br>
begin<br>
writeln(v);<br>
end;<br>
<br>
procedure RTest2.println;<br>
begin<br>
ptr^.println;<br>
end;<br>
<br>
class operator RTest2.:=(c: PTestRec2): RTest2;<br>
begin<br>
result := default(RTest2);<br>
result.ptr := c;<br>
if c <> nil then<br>
InterlockedIncrement(c^.rc);<br>
end;<br>
<br>
class operator RTest2.Initialize(var aRec: RTest2);<br>
begin<br>
aRec.ptr := nil;<br>
end;<br>
<br>
class operator RTest2.finalize(var aRec: RTest2);<br>
begin<br>
if aRec.ptr <> nil then<br>
if InterlockedDecrement(aRec.ptr^.rc) = 0 then<br>
dispose(aRec.ptr);<br>
end;<br>
<br>
class operator RTest2.AddRef(var aRec: RTest2);<br>
begin<br>
if aRec.ptr <> nil then<br>
InterlockedIncrement(aRec.ptr^.rc);<br>
end;<br>
var</div>
<div> r2: RTest2;<br>
begin<br>
r2 := TTestRec2.Create(123);<br>
r2.println;</div>
<div>/////////////////////////////////////////////////////////<br>
</div>
<div>
</div>
<div><br>
</div>
<div><br>
</div>
<div><br>
</div>
<div><br>
</div>
<div>Not sure if it is actually faster. That needs to be
investigated.</div>
<div><br>
</div>
<div>But it definitely helps with the memory usage:</div>
<div><br>
</div>
<div> writeln(ttest.InstanceSize);<br>
writeln(ttestrec.InstanceSize);<br>
writeln(sizeof(ttestrec2));<br>
</div>
<div><br>
</div>
<div>40<br>
16<br>
8<br>
<br>
</div>
<div>With many small objects it should be faster just because it
fits better in the cache.<br>
</div>
<div></div>
<div><br>
Cheers,<br>
Benito </div>
<div class="moz-cite-prefix">On 17.02.21 14:31, Marco van de Voort
via fpc-pascal wrote:<br>
</div>
<blockquote type="cite"
cite="mid:c51f7904-379a-ec4f-82a6-54ff8a4e0987@pascalprogramming.org">
<br>
Op 2021-02-17 om 00:02 schreef Benito van der Zander via
fpc-pascal:
<br>
<blockquote type="cite">
<blockquote type="cite">
<br>
And there often is a lot of unintentional deep copying. This
is also why a property returning a record is fairly useless
except for extremely small records like TPoint (and even that
is not optimal no </blockquote>
<br>
But a managed record to replace an interface, would only contain
a single pointer/class ref. That can be copied fast
<br>
</blockquote>
<br>
(1) A record is not a pointer. So that would require some implicit
referencing in the property
<br>
<br>
(2) If it was managed, it would be an allocation, so I don't
understand this.
<br>
<br>
<br>
_______________________________________________
<br>
fpc-pascal maillist - <a class="moz-txt-link-abbreviated" href="mailto:fpc-pascal@lists.freepascal.org">fpc-pascal@lists.freepascal.org</a>
<br>
<a class="moz-txt-link-freetext" href="https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal">https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal</a>
<br>
</blockquote>
</body>
</html>