<div dir="ltr"><div class="gmail_extra"><div class="gmail_quote">First of all there was small bug in my previous code: wrong usage of Finalize, lack of SmartFinalize and bad parameter for Implicit (keep in mind that this structure will be complemented for TWeakPtr). Correct version:<br><br></div><div class="gmail_quote">======begin code======<br>type<br> TSmartPtr<T> = record<br> // similar as overloading [] operators for property x[v: string]: integer read gx write sx; default;<br> Instance: T; default; // default keyword for non property, can be used only for field of pointer type.<br> RefCount: PLongint;<br><br> procedure SmartFinalize();<br><br> class operator Initialize(var aRec: TSmartPtr<T>);<br> class operator Finalize(var aRec: TSmartPtr<T>);<br> class operator Copy(constref aSource: TSmartPtr<T>; var aDest: TSmartPtr<T>);<br><br> // implicit or explicit operator should be used before "default" field<br> operator Implicit(const aValue: T); // special version of Implicit/Explicit is also needed (available only when is used default for field)<br> operator Explicit: TRawSmartPtr;<br> end;<br><br>procedure TSmartPtr<T>.SmartFinalize();<br>begin<br> if RefCount <> nil then<br> if InterLockedDecrement(RefCount^)=0 then<br> begin<br> Dispose(RefCount);<br> Dispose(Instance);<br> end;<br>end;<br><br>class operator TSmartPtr<T>.Initialize(var aRec: TSmartPtr<T>);<br>begin<br> aRec.RefCount := nil;<br>end;<br><br>class operator TSmartPtr<T>.Finalize(var aRec: TSmartPtr<T>);<br>begin<br> aRec.SmartFinalize();<br>end;<br><br>class operator TSmartPtr<T>.Copy(constref aSource: TSmartPtr<T>; var aDest: TSmartPtr<T>);<br>begin<br> if aDest.RefCount <> nil then<br> Finalize(aDest);<br> if aSource.RefCount <> nil then<br> InterLockedIncrement(aSource.RefCount^);<br> aDest.RefCount := aSource.RefCount;<br> aDest.Instance := aSource.Instance;<br>end;<br><br>operator TSmartPtr<T>.Implicit(const aValue: T);<br>begin<br> if aDest.RefCount <> nil then<br> aDest.SmartFinalize();<br><br> New(RefCount);<br> RefCount^ := 0;<br><br> InterLockedIncrement(RefCount^);<br> Instance := aValue;<br>end;<br><br>operator TSmartPtr<T>.Explicit: TRawSmartPtr;<br>begin<br> Result.RefCount := RefCount;<br> Result.Instance := Instance;<br>end; <br></div><div class="gmail_quote">======end code======<br></div><div class="gmail_quote"><br>2015-10-10 9:59 GMT+02:00 Sven Barth <span dir="ltr"><<a href="mailto:pascaldragon@googlemail.com" target="_blank">pascaldragon@googlemail.com</a>></span>:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><span><p>Would you please explain why you'd need this raw structure besides for printing the RecCounts? (honest question, maybe I'm still too tired ;) )<br></p></span><span>
<p></p></span></blockquote><div>There is no way to access RecCount from <span style="font-size:12.8px">TSmartPtr. When is used "default" inside </span><span style="font-size:12.8px">TSmartPtr (or inside any other record), </span><span style="font-size:12.8px">TSmartPtr</span><span style="font-size:12.8px"> works only as proxy object to "Instance" field. (!) but to perform functionality is necessary to treat Implicit and Explicit operators as operators with higher priority than "default" field, an example:</span></div><div><span style="font-size:12.8px"><br></span></div><div><span style="font-size:12.8px">===begin </span><span style="font-size:12.8px"><span style="font-size:12.8px">code</span>===<br></span></div><div><span style="font-size:12.8px">var</span></div><div><span style="font-size:12.8px"> x: TSmartPtr<PInteger>;</span></div><div><span style="font-size:12.8px"> i: Integer;</span></div><div><span style="font-size:12.8px">begin</span></div><div><span style="font-size:12.8px"> x := New(PInteger); // Implicit operator instead of default "Instance" field (the operator </span><span style="font-size:12.8px">Implicit</span><span style="font-size:12.8px"> </span><span style="font-size:12.8px">has precedence)</span></div><div><span style="font-size:12.8px"> WriteLn(x^); // default field "Instance" is used, will print some random number <br></span></div><div><span style="font-size:12.8px"> x := 'foo'; // Error: Incompatible types: got "Constant String" expected "PInteger" (no Implicit operator found so is used </span><span style="font-size:12.8px"> </span><span style="font-size:12.8px">default "Instance" field</span><span style="font-size:12.8px"> </span></div><div><span style="font-size:12.8px"> i := x.RecCount; // Error: Illegal qualifier (no implicit operator found so is used </span><span style="font-size:12.8px">default "Instance" field</span><span style="font-size:12.8px">)</span></div><div><span style="font-size:12.8px"> </span><span style="font-size:12.8px">TSmartPtr<PInteger>(x).Instance^ := 10; //</span><span style="font-size:12.8px"> Error: Illegal type conversion: "PInteger" to </span><span style="font-size:12.8px">TSmartPtr<</span><span style="font-size:12.8px">PInteger</span><span style="font-size:12.8px">> (no Explicit operator found for </span><span style="font-size:12.8px">TSmartPtr so is used proxy default "Instance" field. </span></div><div><span style="font-size:12.8px"> // Btw</span><span style="font-size:12.8px"> Explicit nor Implicit operator has no sense here because "default" field will be always block access for other record structures</span><span style="font-size:12.8px">)</span></div><div><span style="font-size:12.8px"> // in that situation we need raw structure with similar memory/structures layout</span></div><div><span style="font-size:12.8px"><br></span></div><div><span style="font-size:12.8px"> </span><span style="font-size:12.8px">TRawSmartPtr(x).Instance^ := 5; </span><span style="font-size:12.8px">// Explicit operator instead of default "Instance" field (the operator Explicit </span><span style="font-size:12.8px">has precedence)</span></div><div><span style="font-size:12.8px">end;<br></span></div><div><span style="font-size:12.8px">===end code===<br></span></div><div><span style="font-size:12.8px"><br></span></div><div><span style="font-size:12.8px">!!! WARNING -> </span><span style="font-size:12.8px">Explicit</span><span style="font-size:12.8px"> and Implicit in that case is </span><span style="font-size:12.8px"><span lang="en"><span>different </span></span>than standard Explicit / Implicit. To be precise we have two new operators:</span></div><div><span style="font-size:12.8px"><br></span></div><div><span style="font-size:12.8px">===begin code===<br></span></div><div><span style="font-size:12.8px">operator Explicit: A; <br></span></div><div><span style="font-size:12.8px">operator Implicit(const Value: B);<br></span><span style="font-size:12.8px"><span style="font-size:12.8px">// there is no class keyword before declaration, look at example implementation of TSmartPtr<br></span></span></div><div><span style="font-size:12.8px"><span style="font-size:12.8px">===end code===</span> </span><span style="font-size:12.8px"></span></div><div><span style="font-size:12.8px"><br></span></div><div><span style="font-size:12.8px">these two operators have a higher priority than "default" field, and "default" field have higher priority than any other field/property/operator/method/const/type inside record structure. When "default" is used for field then we don't have direct access to record. New variant of Explicit operator and raw structure is IMO elegant way to get access for original record fields.<br></span></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><p>This is where we reach the dangerous territory ;)<br>
The problem with "default" is how to differentiate from a normal field usage of the record? Keep in mind that a feature might be used in different contexts than one first imagined. So how to ensure that one can access field X of the record and not field X of the default?<br></p></blockquote><div>I know it is risky :P. In attached proposition, problem of overloading operators like "@", ".", "^" is omitted. You need to start thinking about "default" as proxy. Mentioned problem don't exist because programmer can access only "Instance" field (but not directly, for this is used "compiler magic"). The only place where exist access to record structures is implementation of this record. From implementation is possible access to any field or property. Inside implementation of record with "default" field, "default" field has no effect:<br><br></div><div>===begin code===<br></div><div>type<br></div><div> TFoo = record<br> { ... }<br></div><div> a: PInteger; default;<br> property x[v: string]: integer read gx write sx; default;<br><br></div><div> procedure Foo;<br></div><div> end;<br><br></div><div>procedure TFoo.Foo()<br></div><div>begin<br></div><div> Self['x'] := 10; // is ok<br></div><div>end;<br><br></div><div>var<br></div><div> f: TFoo;<br></div><div>begin<br></div><div> f['x'] := 10; // equivalent of f.a['x'] := 10;<br> // ^^^ Error: Incompatible types: got "Constant String" expected "LongInt" <br></div><div>===end code===<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><p>
Also for classes: is Instance a ^T as well or merely a T?</p></blockquote><div>You are right, my bad. I was tired :P.<span> We need only "T" even for TSmartPtr. <br></span></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><span>
</span><p>I suppose Finalize here calls TSmartPtr<>.Finalize and not System.Finalize? We don't usually have directly callable operators, so keep that in mind.</p><span>
<p></p></span></blockquote><div>Right. Fixed on top this message ;). <br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><span><p></p>
</span><p>Only behind a modeswitch or maybe even a mode Oxygene please. And take care with prefixes, they are a PITA to handle as I've already told you ;)</p>
<p></p></blockquote><span id="result_box" class="" lang="en"><span class=""><span id="result_box" class="" lang="en"><span class="">do not scare me!<br><br></span></span></span></span></div><div class="gmail_quote"><span id="result_box" class="" lang="en"><span class=""><span id="result_box" class="" lang="en"><span class="">Wit presented syntax is possible to create many variants of Smart Pointers with different functionality. Influence of "default" field can may be weakened by introducing new operators like new Implicit / Explicit (for example operator TypeInfo).<br> <br></span></span></span></span></div><div class="gmail_quote"><span id="result_box" class="" lang="en"><span class=""><span id="result_box" class="" lang="en"><span class="">Few more examples:<br></span></span></span></span></div><div class="gmail_quote"><span id="result_box" class="" lang="en"><br></span><div><span>var<br></span></div><div><span> a, b: TSmartObj<TObject>;<br></span></div><div><span>begin </span>// <span>TSmartObj<TObject>.Initialize(a); </span><span><span>TSmartObj<TObject>.Initialize(b);</span> </span></div><div><span> a := TObject.Create; // a.Implicit(</span>TObject.Create);<br></div><div><span> b := a; // TSmartObj<TObject>.Copy(a, b);<br></span></div><div><span> FreeAndNil(a); // FreeAndNil(a.Instance);<br></span></div><span> WriteLn(a = b);// a.Instance = b.Instance // print false<br></span></div><div class="gmail_quote"><span> // we need to clear b<br></span></div><div class="gmail_quote"><span> b := nil; // b.Instance := nil;<br></span></div><div class="gmail_quote"><span> WriteLn(TypeInfo(a) = TypeInfo(TSmartObj<TObject>)) // TypeInfo(a.Instance) = TypeInfo(TSmartObj<TObject>) // print false <br><br></span></div>-- <br><div><div dir="ltr"><div>Best regards,<br>Maciej Izak</div></div></div>
</div></div>