> > It would also introduce under-documented determinism into
> the system.
> > One would have to look all the way back to the class definition to
> > find out if an object reference is [Counted].

> Dejan wrote:
>
> No no no :).
>
> Marking a class as [Counted] would simply imbue a reference
> count and maybe some helper functions inside it.
>
> The references can be marked as both [Counted] and uncounted.
> Counted references contribute to the reference count.
> Uncounted (plain, normal) references don't, and this is a)
> necessary in order to avoid cyclic structures and b)
> significantly faster.

The reason why I called this system under-documented is that it would be
mixing deterministic and non-deterministic object collection (or
disposing). The following code might illustrate this:
<code>
public void MyMethod()
{
        MyCountedClass obj1 = new MyCountedClass();
        // <-- Ref count is now 1 on obj1.
        MyUncountedClass obj2 = new MyUncountedClass();

        // Do some work...

        return; // <-- At this point, nothing happens
                // to obj2, but obj1 ref count is decr'mntd
                // and its Dispose method is called().
}
</code>

The problem would be that the class name would generally not be so cute
as to document its reference counting behavior. So on the return of this
method (or if an exception were thrown) Dispose would happen on one
object but not on another. This is _not_ really a big problem, but I
just wanted to point out this loss of self-documentation from the source
code. Right now (in C#) everything is non-deterministic unless the using
statement is employed. The actual behavior is quite obvious from the C#
code. The behavior from reference counting would not be so obvious by
just looking at the method code.

C++ is so strongly deterministic that your destructors on local objects
will get called even when an exception occurs. This is why CLR support
would be handy. The CLR stack unwinding code could account for [Counted]
objects and call their Dispose methods without having to generate a
bunch of try...finally blocks to handle this.

Other than these few minor issues I think this would be a great feature
to add to the CLR.

Here is one idea: What about having a base class for Counted objects
rather than an attribute? The class would go like this:

<code>
public class CountedObject : Object, Disposable
{
        private Int32 _refCount = 0;

        public virtual void Dispose()
        {
        }

        // These methods are really even more private and should be only
called by the CLR
        internal void AddRef()
        {
                Interlocked.Increment(ref _refCount);
        }

        internal void Release()
        {
                if(0 == Interlocked.Decrement(ref _refCount))
                {
                        Dispose();
                }
        }
}
</code>

The derived dispose methods would have to be multiple call tolerant (as
should all Dispose methods...).

The disadvantage of this would be that many system object (such as GDI+
resources, etc.) that could benefit from this would have to be remapped
to a new base class. Also certain classes (such as Component) would not
be counted. But this might simplify implementation.

If just the attribute were used instead of the base class, then the
compiler would have to examine all base classes to see if any base
classes has marked itself with [Counted]. If this is the first class in
the hierarchy with the [Counted] attribute then the compiler would
automatically add the requisite members.

--
Peter

You can read messages from the Advanced DOTNET archive, unsubscribe from Advanced 
DOTNET, or
subscribe to other DevelopMentor lists at http://discuss.develop.com.

Reply via email to