Jump to page: 1 2
Thread overview
scope(~this)
Mar 12, 2017
Inquie
Mar 12, 2017
Stefan Koch
Mar 12, 2017
Inquie
Mar 13, 2017
Nicholas Wilson
Mar 13, 2017
Inquie
Mar 14, 2017
thedeemon
Mar 14, 2017
Inquie
Mar 15, 2017
thedeemon
Mar 15, 2017
Inquie
Mar 15, 2017
thedeemon
Mar 15, 2017
Basile B.
Mar 15, 2017
Ali Çehreli
Mar 15, 2017
H. S. Teoh
Mar 15, 2017
Adam D. Ruppe
Mar 15, 2017
H. S. Teoh
Mar 16, 2017
Basile B.
Mar 16, 2017
Basile B.
March 12, 2017
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.



March 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)
March 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:
>> Is there any easy way to create a scope for termination of the object?
>>
>> [...]
>
> scope(exit)

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.


March 13, 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.



March 13, 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:
>> 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.

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.
















March 14, 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:
>> 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)
>>>    }
>>>
>>> }
>>>

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'.
March 14, 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:
>> 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:
>>>> 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)
>>>>    }
>>>>
>>>> }
>>>>
>
> 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'.

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.

>>>>       ScopeThis!("dealloc(x);")

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.




March 15, 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.
March 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:
>> [...]
>
> 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.

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;
}
March 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:
>> 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.

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.

« First   ‹ Prev
1 2