--
Chromium Developers mailing list: chromi...@chromium.org
View archives, change email options, or unsubscribe:
http://groups.google.com/a/chromium.org/group/chromium-dev
mutable refcounts make verifying multithreaded code much harder.
On Tue, Sep 28, 2010 at 2:40 PM, David Levin <le...@chromium.org> wrote:mutable refcounts make verifying multithreaded code much harder.Can you explain how? To be clear, we already have thread-safe refcounting. We just can't use const on these objects. In my case, allowing it to be const makes it a lot easier to verify that we don't accidentally modify the shared object when we shouldn't.
Some points Darin raised against making refcounts mutable:* Inconsistent with COM and WebKit reference counting.
* Object deletion is basically object mutation. If I pass const Foo* to a function, I don't really expect it to be deleted.
Some points in favor of making refcounts mutable:* scoped_ptr<const Foo> is already allowed. Why not scoped_refptr<const Foo>?
mutable refcounts make verifying multithreaded code much harder.Using a (non-threadsafe) RefCounted object on multiple threads is an unfortunate situation, but it happens, and it would be nice if the coding structures helped one right code correctly.
I don't believe that this check would help in the cases that concern
me the most (where there is a data structure used in multiple threads)
like the database code for instance.
But it is a cool idea. I'll look at that more to see what equivalent
there could be for WebKit. Most of the cross thread task posting goes
through a centralized copy mechanism,
WebCore/platform/CrossThreadCopier.h. It doesn't have a specialization
for RefCounted, only the thread safe variant. However, it does allow
through pointers easily which in retrospec was a bad design decision
that I should fix.
Also, there has been work on something lower level for WebKit
(https://bugs.webkit.org/show_bug.cgi?id=31639) and I'm hopeful we'll
be able to put some effort there and land it in the not too distant
future.
dave
The only issue I have with it is that many team members understand the different of const scoped_ptr<T> and scoped_ptr<const T> and their logical mapping to T* const and T const*. Ask someone with a Java background what it means and why they seem "inversed".What I'm afraid of is the members that don't understand yet and yet fail to ask for help.
Maybe a wiki page with all Peter's knowledge dumped in directly linked in the scoped_refptr class definition?
I don't think there's anything inherently damaging about having mutable, but the high situations described where this seems interesting largely revolves around wanting to create immutable objects.However, I also have any discussion about alternatives while preserving the status quo ref counting semantics.How bad is it really to either force initialization via a constructor, or get people to apply a builder pattern (http://en.wikipedia.org/wiki/Builder_pattern) if the initialization gets too complex? That's how this is often dealt with in language that don't have const.Having an API that fundamentally doesn't expose mutation is arguably an even stronger statement of "don't change me" than annotating a type with constness. You also get separation of initialization/validation logic from the "meat of the class." The worst case cost is a builder object.Note that I'm not suggesting creating a bunch of "read-only interfaces" that everything inherits from.Is this style deemed too annoying?-Albert
I don't think there's anything inherently damaging about having mutable, but the high situations described where this seems interesting largely revolves around wanting to create immutable objects.However, I also have any discussion about alternatives while preserving the status quo ref counting semantics.How bad is it really to either force initialization via a constructor, or get people to apply a builder pattern (http://en.wikipedia.org/wiki/Builder_pattern) if the initialization gets too complex? That's how this is often dealt with in language that don't have const.Having an API that fundamentally doesn't expose mutation is arguably an even stronger statement of "don't change me" than annotating a type with constness. You also get separation of initialization/validation logic from the "meat of the class." The worst case cost is a builder object.Note that I'm not suggesting creating a bunch of "read-only interfaces" that everything inherits from.Is this style deemed too annoying?
I'm fine with the change as I disagree that object deletion is object mutation.
Ref counting is a way to emulate a heap with GC. In no way in languages with a GC the refcounting is part of the object. For example 'const' objects like strings in python/java/C# are still "refcounted". In C++ we tend to optimize refcounting by keeping it inside the object to save one pointer and one heap allocation.
In C++ const object references tend to be a pain on the long run, especially when it starts to involve virtual functions and members acting as a cache. But that's exactly to fix race conditions caused by this kind of design that one would like to enforce const reference.I'm also fine with the other pattern to use const members and use a build factory when necessary.So in short I don't care either way.M-ALe 30 septembre 2010 20:06, Albert J. Wong (王重傑) <ajw...@chromium.org> a écrit :I don't think there's anything inherently damaging about having mutable, but the high situations described where this seems interesting largely revolves around wanting to create immutable objects.However, I also have any discussion about alternatives while preserving the status quo ref counting semantics.How bad is it really to either force initialization via a constructor, or get people to apply a builder pattern (http://en.wikipedia.org/wiki/Builder_pattern) if the initialization gets too complex? That's how this is often dealt with in language that don't have const.Having an API that fundamentally doesn't expose mutation is arguably an even stronger statement of "don't change me" than annotating a type with constness. You also get separation of initialization/validation logic from the "meat of the class." The worst case cost is a builder object.Note that I'm not suggesting creating a bunch of "read-only interfaces" that everything inherits from.Is this style deemed too annoying?
On Thu, Sep 30, 2010 at 5:10 PM, Marc-Antoine Ruel <mar...@google.com> wrote:I'm fine with the change as I disagree that object deletion is object mutation.Ok, thanks!Ref counting is a way to emulate a heap with GC. In no way in languages with a GC the refcounting is part of the object. For example 'const' objects like strings in python/java/C# are still "refcounted". In C++ we tend to optimize refcounting by keeping it inside the object to save one pointer and one heap allocation.Yeah, I think this is a case of an implementation detail leaking out into the interface. shared_ptr doesn't have this restriction (and you don't have to have the separate heap allocation if you use make_shared).In C++ const object references tend to be a pain on the long run, especially when it starts to involve virtual functions and members acting as a cache. But that's exactly to fix race conditions caused by this kind of design that one would like to enforce const reference.I'm also fine with the other pattern to use const members and use a build factory when necessary.So in short I don't care either way.M-ALe 30 septembre 2010 20:06, Albert J. Wong (王重傑) <ajw...@chromium.org> a écrit :I don't think there's anything inherently damaging about having mutable, but the high situations described where this seems interesting largely revolves around wanting to create immutable objects.However, I also have any discussion about alternatives while preserving the status quo ref counting semantics.How bad is it really to either force initialization via a constructor, or get people to apply a builder pattern (http://en.wikipedia.org/wiki/Builder_pattern) if the initialization gets too complex? That's how this is often dealt with in language that don't have const.Having an API that fundamentally doesn't expose mutation is arguably an even stronger statement of "don't change me" than annotating a type with constness. You also get separation of initialization/validation logic from the "meat of the class." The worst case cost is a builder object.Note that I'm not suggesting creating a bunch of "read-only interfaces" that everything inherits from.Is this style deemed too annoying?Yep, the builder pattern is roughly what Darin suggested. As I noted earlier, that requires a lot more boilerplate, when I just want to write scoped_refptr<const Foo>. Also, scoped_refptr<const Foo> makes it clear it is a reference to a const object. Otherwise, we need a convention for the wrapper type to be named ImmutableFoo or ConstFoo something.
Clearly the builder pattern works. But if scoped_refptr<const Foo> is not considered harmful, then it's unnecessary to force users to write extra code.
On Thu, Sep 30, 2010 at 5:28 PM, William Chan (陈智昌) <will...@chromium.org> wrote:On Thu, Sep 30, 2010 at 5:10 PM, Marc-Antoine Ruel <mar...@google.com> wrote:I'm fine with the change as I disagree that object deletion is object mutation.Ok, thanks!Ref counting is a way to emulate a heap with GC. In no way in languages with a GC the refcounting is part of the object. For example 'const' objects like strings in python/java/C# are still "refcounted". In C++ we tend to optimize refcounting by keeping it inside the object to save one pointer and one heap allocation.Yeah, I think this is a case of an implementation detail leaking out into the interface. shared_ptr doesn't have this restriction (and you don't have to have the separate heap allocation if you use make_shared).In C++ const object references tend to be a pain on the long run, especially when it starts to involve virtual functions and members acting as a cache. But that's exactly to fix race conditions caused by this kind of design that one would like to enforce const reference.I'm also fine with the other pattern to use const members and use a build factory when necessary.So in short I don't care either way.M-ALe 30 septembre 2010 20:06, Albert J. Wong (王重傑) <ajw...@chromium.org> a écrit :I don't think there's anything inherently damaging about having mutable, but the high situations described where this seems interesting largely revolves around wanting to create immutable objects.However, I also have any discussion about alternatives while preserving the status quo ref counting semantics.How bad is it really to either force initialization via a constructor, or get people to apply a builder pattern (http://en.wikipedia.org/wiki/Builder_pattern) if the initialization gets too complex? That's how this is often dealt with in language that don't have const.Having an API that fundamentally doesn't expose mutation is arguably an even stronger statement of "don't change me" than annotating a type with constness. You also get separation of initialization/validation logic from the "meat of the class." The worst case cost is a builder object.Note that I'm not suggesting creating a bunch of "read-only interfaces" that everything inherits from.Is this style deemed too annoying?Yep, the builder pattern is roughly what Darin suggested. As I noted earlier, that requires a lot more boilerplate, when I just want to write scoped_refptr<const Foo>. Also, scoped_refptr<const Foo> makes it clear it is a reference to a const object. Otherwise, we need a convention for the wrapper type to be named ImmutableFoo or ConstFoo something.Couple of commentsFirst, I was suggesting we do _not_ use wrapper types. This gets old really fast.
Rather I was suggesting avoid having mutable objects at all in the cases it matters. This means you'd have 2 types, the "data object" and its associated "builder" or "factory" depending. You wouldn't need an "ImmutableFoo" or "ConstFoo" since there's no "Foo."
As for note the constness of reference object, it's doesn't seem that important if there are no APIs for mutation. It may help readability for people who are glancing through the code, but I've found that in a system with bunches of immutable objects, you get a pretty quick feel for which ones are create-only.But this is starting to get into a pick your preference discussion.Clearly the builder pattern works. But if scoped_refptr<const Foo> is not considered harmful, then it's unnecessary to force users to write extra code.Yeah, in the end, this seems like the argument that holds the most weight.
I'm in favor of supporting scoped_refptr<const X>.On Tue, Sep 28, 2010 at 1:44 PM, William Chan (陈智昌) <will...@chromium.org> wrote:
* Object deletion is basically object mutation. If I pass const Foo* to a function, I don't really expect it to be deleted.I've never really agreed with this. First, it's not _inherently_ wrong to delete a pointer-to-const-object at some point, becauseconst int* x = new int;delete x;...doesn't warn.
It seems we're already converging, but I just wanted to reply to this
comment. I think it is unfortunate to force an entire class to be
immutable when you really only want some instances of the class to be.
The resulting class is much less flexible.
One place where the flexibility is nice is unit testing. With the
builder+class-lacking-setters pattern, a new instance of the class
must be built for each configuration you want to test. I think this
might tend to discourage extensive testing.
I guess this is basically the "too much work" argument, but I wanted
to point out that it manifests in multiple places.
Thanks everyone, this has been an interesting discussion to follow.
- a