Nice code. However that boxed/unboxed code looks a little odd. Not that I couldn't adapt, but I do not find it that intuitive and natural as I would like it to be. Maybe it's just me and I do not see it properly, but I find this smart pointers example code more self explaining:Oh, wow, that is a cheeky way to do this. O.o
https://adugmembers.wordpress.com/2011/12/05/smart-pointers/
I am not an expert so this remark is not based on a topic knowledge, but more on a personal feeling when looking at smart pointers example code.
Nice code. However that boxed/unboxed code looks a little odd. Not that I couldn't adapt, but I do not find it that intuitive and natural as I would like it to be. Maybe it's just me and I do not see it properly, but I find this smart pointers example code more self explaining:Oh, wow, that is a cheeky way to do this. O.o
https://adugmembers.wordpress.com/2011/12/05/smart-pointers/
I am not an expert so this remark is not based on a topic knowledge, but more on a personal feeling when looking at smart pointers example code.
I should probably forward that to Blaise to make sure his implementation of anonymous functions supports that as well. :-[
@avra That implementation is not currently possible (anonymous methods are used).Bummer.
The [box] syntax originated from the current lack of default properties other that array properties.Hopefully we will get other then array default properties so box/unbox can be avoided.
It has a very clear [unbox] option, something the code you refer to lacks.I thought this line from Delphi example was unboxing:
Yes. And there is patch from Maciej.@avra That implementation is not currently possible (anonymous methods are used).Bummer.
Hopefully we will get other then array default properties so box/unbox can be avoided.Yes.
I thought this line from Delphi example was unboxing:If it is, then I find it more natural.
Person1 := nil; // Release early
I am probably missing something, but it is obvious to me. With a little macro help we can even write it like this:QuoteI thought this line from Delphi example was unboxing:If it is, then I find it more natural.
Person1 := nil; // Release early
Here I disagree, handling smartpointers should be recognizable and obvious.
I forgot to mention that you also have - the old - access through the instance.value property if you really do not like the [box] syntax.Yes, I would probably use that until Value is able to become default property.
Aren't these "smart pointers" just C++'s workaround for not having try-finally construct?They also allow for automatic memory management. There's simply no need then to manually free object instances except in specific cases (e.g. circular references) and even then that can be simply done by setting the smart pointer variable to Nil.
Thaddy, I propose a version where the structure only takes the size of a pointer. Instead of the default property and additional "Value" field, I suggest only one "Self" field.That is possible, but relies on the record layout. First field being the same as the pointer to record itself. IMHO that is implementation detail.
If constructor has parameters, then how do you pass that required parameters to constructor?
Of course, if the class does not have a parameterless constructor, then this simply will not compile.Yes, but it has: TObject has..
Of course, if the class does not have a parameterless constructor, then this simply will not compile.Yes, but it has: TObject has..
One note: You can not really use the parameterized constructors on things like TFilestreamOption when the default constructor is not called. For diversity - FPC mode, and as and before, only the size of the pointer.
I have not yet found a Delphi example that would trigger the constructor-constraint of a generic, thus FPC parses, but ignores that constraint (my assumption is that this is from Delphi.NET times).Of course, if the class does not have a parameterless constructor, then this simply will not compile.Yes, but it has: TObject has..
Or not: https://forum.lazarus.freepascal.org/index.php/topic,45366.msg327886.html#msg327886
;)
Do you use {$interfaces corba} by any change? I have never seen the need for that in my TAuto<>. Can you confirm you are using ,y version? and COM? Or are you using any other suggestion from the discussion? In that case I can not help you. My version works different from the code you use, that's why I ask. May be you used the version with management operators? That has issues indeed.My observations are based on code from this discussion (for TAuto<>, not for TGSharedRef<>). I'm not using {$interfaces corba}.
As Warfley observed, the original version( by me) based on an inteface does not suffer the issue.Correct, I can see into the compiler sources that the interfaces are handled quite differently.
It is also easier to use because of auto-create (see Tstringlist example)
Note, that with hindsight I kept the original [box/unbox] syntax, because that allows for explicit release, see the attached example above. My later changes where merely to satisfy customers here.. :DThanks for the effort!
@WarfleyThe interesting bit about the example by Serge is that no copy operation takes place. If we use a constructor also the assignment fails:
Although not 100% sure, the issue with the double finalization (in https://gitlab.com/freepascal.org/fpc/source/-/issues/37164) is related to the creation of the hidden temp variable for the enumerator. So with the simplified example given by Serge Anvarov (ASerge?) for the same issue - when the function result is assigned to a variable, the issue dissapears, when discarded - we have double finalization.
So far, I don't see how the ASerge TAuto<> can be affected by the double finalization issue. Still investigating.
*snip*It is actually about two different examples given by ASerge - one is here for TAuto<> and another one is for the double finalization bug issue : https://gitlab.com/freepascal.org/fpc/source/uploads/43c46a9afc8394afd23b490a50216aec/project1.lpr
I have no clue if ASerge's example that you cite is viable, since it seems not complete, whereas my example is a complete example that always works on any class with a default, parameterless, constructor.
I suppose - as discussed and I acknowledged - that eventually this may very well be the way to go, but as it stands my interface approach has its own merits. It is even Delphi compatible.
*snip
@WarfleyThe thing is, the constructor should be nothing more than a static class function where instead of Result "self" is used. So there should not be a difference from calling the constructor of the type vs having an ordinary function with the return value being the record.
I'm still for the hidden temporary variables,Test2 doesn't suffer from the issue. Test1 involves a temporary.
procedure Test1; var R: TSomeManagedRecord; begin R := TSomeManagedRecord.Create(42); end; procedure Test2; var R, S: TSomeManagedRecord; begin R := S.Create(42); end;
In both cases fpc_copy_proc is not omitted, just fpc_finalize was erroneously called before Create in Test1.
*snip*Exactly! In case of a managed object the memory is (should be) already pre-allocated, so when the type name is used instead of real variable, the compiler makes a hidden temporary and then the issue manifests itself. See highlighted lines 34-36, 47-49, 50-52. Lines 34-36 finalizes the temporary at ebp-56 before constructor invocation (line 39) and the actual copy (line 43):
The thing is, the constructor should be nothing more than a static class function where instead of Result "self" is used. So there should not be a difference from calling the constructor of the type vs having an ordinary function with the return value being the record.
And that is why I think that atm the interface approach works better. No temporaries.Actually the Auto<> is also an advanced record and the issue is there. The good thing is perhaps that the subfields of the record are managed a bit deeper and a bit better by the compiler ... and this circumvents the asymmetrical Initialize/Finalize calls (no need to use them).
But that can change...
P.S. It seems that putting a TInterfacedObject into can be a viable workaround for the enumerator issue also.Maybe, but as enumerators are freed automatically anyway, I can simply use classes. I just wanted to try out if records might be more efficient (as they do not need to allocate memory), so there is no real advantage of using interfaces over classes
so there is no real advantage of using interfaces over classesYou missed the whole point about smart pointers: this can not be done with - pure - classes: automatic memory management (A.K.A. ARC, good or bad, no opinion). Automatic create on reference and automatic release....
FreeAndNil almost always simply hides bad programming. You should almost never need it in a well written program. The fpc/lazarus community seems to favor it, The Delphi community seems to use it with more caution.
It is interesting to know that Delphi dropped ARC, which is a form of global automatic memory management that does not rely on garbage collection.
Well, let's see what ASerge comes up with. This is still relevant and - I think you all agree - a total joy to explore.Sorry, I somehow missed this conversation.
Sorry, I somehow missed this conversation.
The problem with sudden double release is easily solved - I forgot to implement the AddRef method.
So the updated unit...
Well, I'll need to study your update (TAuto) more ASerge.
I like it how I can set the instance pointer directly with your example.
It works, but I have to do more checking to prevent Access violations compared to Thaddy's example (Auto)
But, there's a lot of existing classes you didn't write yourself, where that doesn't work. What do you do?
Well, the easiest way is probably to inherit a new class, that adds and implements an IUnknown interface, like TInterfacedObject does. Or use a smart pointer. The most interesting one is probably this one as posted earlier (https://adugmembers.wordpress.com/2011/12/05/smart-pointers/), which should now work on trunk.
The difference between class methods and other methods is, that the latter get an invisible first parameter, Self, that points to the instance. While class methods are regular functions.
The [box] syntax originated from the current lack of default properties other that array properties.
That is already recorded.
Both AVK and me wrote a proper implementation. Just waiting for a water tight implementation for the default property, which was more or less also implemented in a fork by Maciej. (and as far as I know almost correct, but abandoned?)
Both mentioned implementations work from 3.2 onwards. It is just the sugar candy that does not work yet.
Look up the discussion on this forum.
Maciej, a.k.a HNB on this forum did it. He is not good with the compiler people anymore.
(But he contributed many things to Lazarus and FPC: anchor docking resp rtl-generics and many fixes)