On 06/20/2013 07:21 AM, Till Schneidereit wrote:
> All!
>
> We still don't have a clear line on how to name handles, both in- and
> outside of the engine. Or, if we do, it's pretty unevenly distributed.
The current policy is HandleT inside spidermonkey and xpconnect,
JS::Handle<T*> outside.
> Seeing as how everyone in the world just loves a good discussion about
> naming (and how we should probably get to something resembling consistency
> before handles are used outside the engine too much), let's get this thing
> going, shall we?
I would be happy for this perennial topic to die. Having a discussion
here seems like a plausible way to make it die. So I am fully in support
of this plan. :-)
> Here's my opening gambit, in IRC-based collaboration with @ted and @jonco,
> and opposition from @evilpie:
>
> Options:
> 1. don't use any typedefs at all, so always use (js:: and JS::)Handle<Foo*>
> 2. change the template to the form Handle<Foo>, roughly matching what v8
> does
> 3. use typedefs everywhere, so always use HandleFoo
>
> Personally, I favor the last of these options, because:
> 1. it is the cleanest, least cluttery one
> 2. v8 seems to get by just fine with option 2, somewhat countering the
> argument for option 1 that everything else hides the fact that you're
> dealing with heap values
> 3. Handle<T> isn't a general container people can use with their own Ts, so
> the fact that it's a template in the first place is an implementation
> detail that shouldn't be exposed
> 3. it scales linearly with the number of JSObject subclasses, so isn't
> really going to be a burden going forward
>
> That's all I've got, I think.
I support option #1.
Assuming #2 means using Handle<JSObject> instead of Handle<JSObject*>,
I'm against. First, because of Handle<Value>, which is inconsistent with
Handle<JSObject>. Second, because Handles are mysterious and feel
heavyweight until you realize they're just a double pointer (ok, pointer
to encoded pointer in the case of Value).
Which itself makes sense: I have a pointer to something that may move,
so the pointer value will need to change. How can I avoid changing all
consumers' pointers? By adding a level of indirection: store a pointer
to a movable pointer instead. It's very clear what you're giving up (an
extra dereference on use) and what you're gaining (pointers can now move).
As for #3, this morning on IRC, bz pointed out that he is utilizing the
templateyness *outside* of spidermonkey in the DOM bindings. I think
that's a strong argument for keeping the template exposed.
Expanding on that, if we exposed HandleObject, HandleString,
HandleValue, etc., then I kind of starting thinking: Hey, these things
are all closely related. Wouldn't it be nice if we could use the C++
type system to express that commonality? I know, I'll make my own header
that does
template<typename T>
class MyHandle {
public:
typedef T InnerType;
};
template<>
class MyHandle<JSObject*> {
public:
typedef HandleObject Handle;
};
template<>
class MyHandle<JSStringt*> {
public:
typedef HandleString Handle;
};
.
.
.
there! Now I can use MyHandle<T>::Handle for everything!
template<typename T>
void LogPointer(const MyHandle<T>::Handle& h)
{
printf("rooted %p\n", h.get());
}
...overload for MyHandle<Value>::Handle if needed...
...overload for other pointers that print out a different string...
I'm half kidding, but seriously, if there's *any* reason why somebody
might want to implement something generically against Handles, then we
should expose the commonality via the C++ type system, not conceal it.
And bz has an existence proof in hand. (If our silly compilers just
supported the syntax |friend developer bz;|, then I might change my mind.)
The main counterargument I see to this is if we have such a small set of
externally exposed gcptr types that the commonality doesn't help. In a
quick glace at jspubtd.h, I see:
class JSFlatString;
class JSFunction;
class JSObject;
class JSScript;
class JSStableString;
class JSString;
which is more than enough for me. I also like the idea of being able to
expose new garbage-collectible things in the future. (I'm not thinking
of any of the ones we now have, more about new things.) Also, note that
within spidermonkey there are a lot more types, so the argument for
Handle<T> is stronger.
So put me down for #1. I like exposing Handle<T>, and I'd like to use it
internally in Spidermonkey. I've heard the extra finger typing argument,
but these just show up in parameter lists. Anyway, we have a long
history of lengthening names for precision and documentation. Get
friendly with your < and > keys.
I would also support renaming it everywhere to Local<T>, to better pair
with HeapPtr<T> and stop people from thinking that you should be able to
get a Handle out of a HeapPtr. (Which you can't, because HeapPtr is
using static typing to call the right barriers when you modify it, and
if you lose the static heap-vs-stack distinction casting both to a
Handle, then you'd have to do barriers on both things. Or at least,
dynamically check which one you're holding.) But given that we're
currently exporting Handle<T>, we can make those decisions independently.
I think I had one more point to make, but wracking my memory right now,
I find myself to be pointless. I guess I'd better shut up, then.