digitalmars.D.learn - scope(~this)
- Inquie (23/23) Mar 12 2017 Is there any easy way to create a scope for termination of the
- Stefan Koch (2/5) Mar 12 2017 scope(exit)
- Inquie (5/11) Mar 12 2017 That is for the function, correct? If I release the resource at
- Nicholas Wilson (9/27) Mar 12 2017 If it is COM then you should use IUnknown (the COM root
- Inquie (61/94) Mar 13 2017 Sorry, but that is missing the point! First, it isn't that
- thedeemon (16/39) Mar 13 2017 I think the feature you're asking for is too complicated/involved
- Inquie (33/75) Mar 14 2017 Complexity is in the eye of the beholder. Children think many
- thedeemon (12/18) Mar 15 2017 Here you are. "All the delegates" - where are they stored? This
- Inquie (7/25) Mar 15 2017 If it is trivial, can you write up a quick solution. I don't see
- thedeemon (3/5) Mar 15 2017 Here it is, source and output:
- Basile B. (21/56) Mar 15 2017 I was not sure to answer yesterday because the conversation
- =?UTF-8?Q?Ali_=c3=87ehreli?= (3/22) Mar 15 2017 Wow! Is this specified anywhere or have you come across this by chance? ...
- H. S. Teoh via Digitalmars-d-learn (16/40) Mar 15 2017 [...]
- Adam D. Ruppe (16/24) Mar 15 2017 That's normal mixin template behavior: if the name of a mixed in
- H. S. Teoh via Digitalmars-d-learn (7/11) Mar 15 2017 Filed a bug for it:
- Basile B. (4/12) Mar 16 2017 It's not specified. Found it while trying to understand the
- Basile B. (3/17) Mar 16 2017 (which is __dtor doesn't call the other destructors in the
Is there any easy way to create a scope for termination of the object? I have a template method that takes a type and allocates and deallocates based on that type. class bar { void foo(T)() { T x; alloc(x); scope(~this) dealloc(x); // hypothetical that wraps the statement in a lambda and deallocates in the destructor ... x must stay allocated until class instance termination(has to do with COM, can't release it in foo) } } Now, x cannot be a field because T is unknown(i suppose I could use object, void*, etc, but...). I realize there are ways to work around this. I will create lambdas that release them since that is easiest. I could return x but that creates a mess. Hoping that either something like this exists or could be a feature enhancement.
Mar 12 2017
On Sunday, 12 March 2017 at 21:38:44 UTC, Inquie wrote:Is there any easy way to create a scope for termination of the object? [...]scope(exit)
Mar 12 2017
On Sunday, 12 March 2017 at 22:13:21 UTC, Stefan Koch wrote:On Sunday, 12 March 2017 at 21:38:44 UTC, Inquie wrote:That is for the function, correct? If I release the resource at the end of the function, the COM interface will no longer be valid. It must be done when the class terminates, not the function.Is there any easy way to create a scope for termination of the object? [...]scope(exit)
Mar 12 2017
On Sunday, 12 March 2017 at 21:38:44 UTC, Inquie wrote:Is there any easy way to create a scope for termination of the object? I have a template method that takes a type and allocates and deallocates based on that type. class bar { void foo(T)() { T x; alloc(x); scope(~this) dealloc(x); // hypothetical that wraps the statement in a lambda and deallocates in the destructor ... x must stay allocated until class instance termination(has to do with COM, can't release it in foo) } } Now, x cannot be a field because T is unknown(i suppose I could use object, void*, etc, but...).If it is COM then you should use IUnknown (the COM root interface),or if you are expecting multiple calls to foo, an array of IUnknown. I think the GC will clean up completely for you in either case and call release(?) on the member(s). Also as it is COM you probably don't need to template it, just choose T to be the most recent ancestor of all (old) T's you would be expecting foo to be instantiated with (e.g. IUnknown if you expect any COM object.
Mar 12 2017
On Monday, 13 March 2017 at 05:18:18 UTC, Nicholas Wilson wrote:On Sunday, 12 March 2017 at 21:38:44 UTC, Inquie wrote:Sorry, but that is missing the point! First, it isn't that simple. I do not think the GC will call release as the GC has no idea of COM nor the interfaces. While it might be safe not to release them and let the OS deal with it, this is not standard. The template is to not part of COM but required to dynamically instantiate the COM interface that is not supplied(using GetIDsOfNames). So, the way it work is, I have a function that takes an interface which specifies the dynamic COM functions. Using GetIDsOfNames(since that seems to be the only way) gets the function pointers to these functions in which I build up a new object representing that interface. The problem is, One must use CoCreateInterface to create the COM object to use GetIDsOfNames(neither of which depends on the interface). But CoCreateInterface returns the interface with the Release function as a member and this function must be called later(at terminate of the overall class handling all this stuff). But since I have to create a variable with the interface to get the methods and to pass to CoCreateInstance, and eventually use it to call Release, I can't discard the variable at the end of the function. Basically the interface's lifetime must exist for the entirety of the containing object. Normally one would use the constructor and class fields to manage this, but it is impossible here because the actual interfaces are unknown at compile time(they are extracted from an idl by this class). The only thing I could do is keep an array of all these IUnknown interfaces(sorta using the above technique), since IUnknown has the Release function in it, basically using your suggestion or what I originally said is a feasible solution. But this pollutes the class name space unnecessarily(I know it is just an array, but ultimately should be unnecessary). Rather, if I could simply use a scope(~this) or some other mechanism, everything will be automatically taken care of. scope(~this) X.Release(); would realize that X, the local variable in the function, will be used and the GC will not free it just like delegates do(although it would need to be copied to the heap so future function calls won't corrupt the value when used on the stack, or, alternatively I could malloc it in the function instead). Then, on destruction, the scope is executed. X still exists. In this case, it's 1 line of code rather than about 5(a class field array, an append, and calling release on all appends in the destructor). It's very clear and very precise. It's very similar to scope(exit) for function but for classes(since classes can "exit" too). It may be better to call it scope(this) which is more clear(when the scope of the object instance is over, then "execute" what follows). I think this feature would actually be quite useful. Instead of handling many things in the destructor, we can handle them on site. e.g., any class resources that are allocated could then have a scope(this) right after allocation to deallocate them instead of having to push it in the the destructor which separates the code visually and programmatically. The same argument which is used to make scope(exit) useful, but on a higher level... Which, if we follow it, we should then also have scope(application) or something for application level scope.Is there any easy way to create a scope for termination of the object? I have a template method that takes a type and allocates and deallocates based on that type. class bar { void foo(T)() { T x; alloc(x); scope(~this) dealloc(x); // hypothetical that wraps the statement in a lambda and deallocates in the destructor ... x must stay allocated until class instance termination(has to do with COM, can't release it in foo) } } Now, x cannot be a field because T is unknown(i suppose I could use object, void*, etc, but...).If it is COM then you should use IUnknown (the COM root interface),or if you are expecting multiple calls to foo, an array of IUnknown. I think the GC will clean up completely for you in either case and call release(?) on the member(s). Also as it is COM you probably don't need to template it, just choose T to be the most recent ancestor of all (old) T's you would be expecting foo to be instantiated with (e.g. IUnknown if you expect any COM object.
Mar 13 2017
On Monday, 13 March 2017 at 14:28:01 UTC, Inquie wrote:On Monday, 13 March 2017 at 05:18:18 UTC, Nicholas Wilson wrote:I think the feature you're asking for is too complicated/involved for a language feature. Because it means there must be some implicit array in each object of your 'bar' class that holds some number of closures that will be executed in destructor. This affects object's memory layout and raises questions of allocating memory for those closures and since those closures will have pointers to some data (like 'x' here) it affects garbage collection. So there are a lot of things to be careful about and things that might affect other language features we haven't thought about yet. This is something quite big and something that affects a lot of code, not just a couple of classes you'll write in your one app. Probably it would be better to implement it as a library feature. Just make a base class having a method for registering such closures and calling them in destructor, and inherit from it or just embed it in your 'bar'.On Sunday, 12 March 2017 at 21:38:44 UTC, Inquie wrote:Is there any easy way to create a scope for termination of the object? I have a template method that takes a type and allocates and deallocates based on that type. class bar { void foo(T)() { T x; alloc(x); scope(~this) dealloc(x); // hypothetical that wraps the statement in a lambda and deallocates in the destructor ... x must stay allocated until class instance termination(has to do with COM, can't release it in foo) } }
Mar 13 2017
On Tuesday, 14 March 2017 at 05:33:28 UTC, thedeemon wrote:On Monday, 13 March 2017 at 14:28:01 UTC, Inquie wrote:Complexity is in the eye of the beholder. Children think many things are complex when they are not. If a library solution could be created that is as seamless as a language solution, then I guess it would work. The downside of a library solution is uniformity of syntax and added verbosity. There is really no any arrays to keep track of or anything like that matter you stated. It requires creating a delegate to wrap the scope block and a copy of the variable to one on the heap. The GC uses arrays and that happens regardless. No reason for the compiler to create a new array. 3 steps: 1. Compiler copies local variables to heap(the "closure" part, which actually means it is not closing anything as a normal delegate would require). 2. The compiler creates a delegate. No big deal, does this in many places. 3. The compiler calls all the delegates on destruction. The only new part. But not difficult. Create a ScopeThis(...) and adds no extra overhead would be nice but I see that as being more complex. How can we determine what are variables that need to be copied to the heap? How can we hook in to the ~this? (can't have multiple ones, can we?) If you can come up with a working ScopeThis that doesn't have any more overhead than a language version, I'd be all for it, I don't know or see how it could be done.On Monday, 13 March 2017 at 05:18:18 UTC, Nicholas Wilson wrote:I think the feature you're asking for is too complicated/involved for a language feature. Because it means there must be some implicit array in each object of your 'bar' class that holds some number of closures that will be executed in destructor. This affects object's memory layout and raises questions of allocating memory for those closures and since those closures will have pointers to some data (like 'x' here) it affects garbage collection. So there are a lot of things to be careful about and things that might affect other language features we haven't thought about yet. This is something quite big and something that affects a lot of code, not just a couple of classes you'll write in your one app. Probably it would be better to implement it as a library feature. Just make a base class having a method for registering such closures and calling them in destructor, and inherit from it or just embed it in your 'bar'.On Sunday, 12 March 2017 at 21:38:44 UTC, Inquie wrote:Is there any easy way to create a scope for termination of the object? I have a template method that takes a type and allocates and deallocates based on that type. class bar { void foo(T)() { T x; alloc(x); scope(~this) dealloc(x); // hypothetical that wraps the statement in a lambda and deallocates in the destructor ... x must stay allocated until class instance termination(has to do with COM, can't release it in foo) } }Must determine that x is a variable(hard?) and copy it to the heap(easy). Must create access to any local functions used(e.g., if dealloc is local). Then must hook in to ~this to execute the code. It would be nicer to not have to use a string but it would work easy since we could use a mixin and modify the string easily once we could parse it.ScopeThis!("dealloc(x);")
Mar 14 2017
On Tuesday, 14 March 2017 at 14:35:11 UTC, Inquie wrote:There is really no any arrays to keep track of or anything like that matter you stated. ... 3 steps: ... 3. The compiler calls all the delegates on destruction.Here you are. "All the delegates" - where are they stored? This is the array of delegates I was talking about. In a library solution you don't even need to think about the string mixins and variables copying. Just make a method that takes a delegate. Then call it like this: scopeThis({ dealloc(x); }); The compiler will create the delegate for you and store x in the heap in the first place. In scopeThis() you just add the passed delegate to an array of other delegates, then in destructor call them. Seems rather trivial, I don't see a need for a language feature that affects all the classes and objects.
Mar 15 2017
On Wednesday, 15 March 2017 at 08:17:11 UTC, thedeemon wrote:On Tuesday, 14 March 2017 at 14:35:11 UTC, Inquie wrote:If it is trivial, can you write up a quick solution. I don't see how to accomplish it easily. If ScopeThis({dealloc(x);}); copies locals to the heap, then that solves part 1 trivially. But a bit of CT reflection is required to store the delegates in the class and I don't see it as being trivial... although it very well might be.There is really no any arrays to keep track of or anything like that matter you stated. ... 3 steps: ... 3. The compiler calls all the delegates on destruction.Here you are. "All the delegates" - where are they stored? This is the array of delegates I was talking about. In a library solution you don't even need to think about the string mixins and variables copying. Just make a method that takes a delegate. Then call it like this: scopeThis({ dealloc(x); }); The compiler will create the delegate for you and store x in the heap in the first place. In scopeThis() you just add the passed delegate to an array of other delegates, then in destructor call them. Seems rather trivial, I don't see a need for a language feature that affects all the classes and objects.
Mar 15 2017
On Wednesday, 15 March 2017 at 12:56:10 UTC, Inquie wrote:If it is trivial, can you write up a quick solution. I don't see how to accomplish it easily.Here it is, source and output: https://dpaste.dzfl.pl/bbf162529c6c
Mar 15 2017
On Tuesday, 14 March 2017 at 14:35:11 UTC, Inquie wrote:On Tuesday, 14 March 2017 at 05:33:28 UTC, thedeemon wrote:I was not sure to answer yesterday because the conversation turned on the COM thing. I wanted to say that you can use a mixin template because they can introduce destructors that are called automatically with the aggregate destrcutor mixin template Foo(T) { T x; void foo() { alloc(x); } ~this() // auto-called by the target aggregate { dealloc(x); } } class bar { mixin Foo!Stuff; }[...]Complexity is in the eye of the beholder. Children think many things are complex when they are not. If a library solution could be created that is as seamless as a language solution, then I guess it would work. The downside of a library solution is uniformity of syntax and added verbosity. There is really no any arrays to keep track of or anything like that matter you stated. It requires creating a delegate to wrap the scope block and a copy of the variable to one on the heap. The GC uses arrays and that happens regardless. No reason for the compiler to create a new array. 3 steps: 1. Compiler copies local variables to heap(the "closure" part, which actually means it is not closing anything as a normal delegate would require). 2. The compiler creates a delegate. No big deal, does this in many places. 3. The compiler calls all the delegates on destruction. The only new part. But not difficult. Create a ScopeThis(...) and adds no extra overhead would be nice but I see that as being more complex. How can we determine what are variables that need to be copied to the heap? How can we hook in to the ~this? (can't have multiple ones, can we?) If you can come up with a working ScopeThis that doesn't have any more overhead than a language version, I'd be all for it, I don't know or see how it could be done.Must determine that x is a variable(hard?) and copy it to the heap(easy). Must create access to any local functions used(e.g., if dealloc is local). Then must hook in to ~this to execute the code. It would be nicer to not have to use a string but it would work easy since we could use a mixin and modify the string easily once we could parse it.[...]
Mar 15 2017
On 03/15/2017 03:23 AM, Basile B. wrote:you can use a mixin template because they can introduce destructors that are called automatically with the aggregate destrcutor mixin template Foo(T) { T x; void foo() { alloc(x); } ~this() // auto-called by the target aggregate { dealloc(x); } } class bar { mixin Foo!Stuff; }Wow! Is this specified anywhere or have you come across this by chance? :) Ali
Mar 15 2017
On Wed, Mar 15, 2017 at 12:34:32PM -0700, Ali Çehreli via Digitalmars-d-learn wrote:On 03/15/2017 03:23 AM, Basile B. wrote:[...] Whoa. This is a really bizarre unknown (AFAICT) bit of the language (or at least, dmd's implementation thereof). I just did a bit of local testing, and found that while dmd happily chains mixin template dtors into an aggregate, it behaves erratically if the mixin template declares this(). It works if there's only a single this() declared either in the class itself, or a single mixin template. But if the class declares this() and the (single) mixin template also declares this(), then the mixin template's version is ignored and the class-declared this() is run upon construction. However, if there are two mixin templates both declaring this(), the compiler dies with an ICE. :-D T -- It is widely believed that reinventing the wheel is a waste of time; but I disagree: without wheel reinventers, we would be still be stuck with wooden horse-cart wheels.you can use a mixin template because they can introduce destructors that are called automatically with the aggregate destrcutor mixin template Foo(T) { T x; void foo() { alloc(x); } ~this() // auto-called by the target aggregate { dealloc(x); } } class bar { mixin Foo!Stuff; }Wow! Is this specified anywhere or have you come across this by chance? :)
Mar 15 2017
On Wednesday, 15 March 2017 at 20:36:27 UTC, H. S. Teoh wrote:But if the class declares this() and the (single) mixin template also declares this(), then the mixin template's version is ignored and the class-declared this() is run upon construction.That's normal mixin template behavior: if the name of a mixed in object already exists in the instantiation scope, the existing one is preferred. This allows you to "override" mixin functions and is quite useful. You can also bring in the others via alias. See my tip here for a related factoid: http://arsdnet.net/this-week-in-d/2016-feb-07.html That's what I *thought* was going on with the destructor too... but I confirmed both do in fact exist and seem to be merged by the compiler. I knew it did that with static dtors, but the spec says "a class can have only one destructor and it is always virtual" so idk what's going on. Bug, perhaps, but I now am inclined to believe it is a hidden feature. Important note though: such behavior is already possible. Struct dtors of members are called when the class dtor runs too...However, if there are two mixin templates both declaring this(), the compiler dies with an ICE. :-Deek.
Mar 15 2017
On Wed, Mar 15, 2017 at 08:55:34PM +0000, Adam D. Ruppe via Digitalmars-d-learn wrote: [...]Filed a bug for it: https://issues.dlang.org/show_bug.cgi?id=17259 T -- Meat: euphemism for dead animal. -- FloraHowever, if there are two mixin templates both declaring this(), the compiler dies with an ICE. :-Deek.
Mar 15 2017
On Wednesday, 15 March 2017 at 19:34:32 UTC, Ali Çehreli wrote:On 03/15/2017 03:23 AM, Basile B. wrote:It's not specified. Found it while trying to understand the difference between __dtor and __xdtor. But this is clearly designed to work this way. Not really an hidden gem.you can use a mixin template because they can introduce destructors that are called automaticallywith theaggregate destrcutorWow! Is this specified anywhere or have you come across this by chance? :) Ali
Mar 16 2017
On Thursday, 16 March 2017 at 07:49:19 UTC, Basile B. wrote:On Wednesday, 15 March 2017 at 19:34:32 UTC, Ali Çehreli wrote:(which is __dtor doesn't call the other destructors in the aggregate, xdtor does)On 03/15/2017 03:23 AM, Basile B. wrote:It's not specified. Found it while trying to understand the difference between __dtor and __xdtor.you can use a mixin template because they can introduce destructors that are called automaticallywith theaggregate destrcutorWow! Is this specified anywhere or have you come across this by chance? :) Ali
Mar 16 2017