Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

What's in a (handle's) name?

89 views
Skip to first unread message

Till Schneidereit

unread,
Jun 20, 2013, 10:21:29 AM6/20/13
to JS Internals list
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.

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?

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.


till

Bobby Holley

unread,
Jun 20, 2013, 12:41:31 PM6/20/13
to Till Schneidereit, JS Internals list
I like the typedefs myself. But more fundamentally, I believe pretty
strongly that we should do the same thing in and outside of the JS engine
(so that, in particular, JS hackers are eating their own dogfood). I've
mandated this by fiat in XPConnect, but also believe that the current
mandate of "typedefs in the engine, templates in the browser" is
undesirable.

Using the templates in the browser is particularly crappy because browser
code generally doesn't |using namespace JS|. So you end up having to
namespace-qualify twice: JS::MutableHandle<JS::Value>

bholley


On Thu, Jun 20, 2013 at 7:21 AM, Till Schneidereit
<tschne...@gmail.com>wrote:
> _______________________________________________
> dev-tech-js-engine-internals mailing list
> dev-tech-js-en...@lists.mozilla.org
> https://lists.mozilla.org/listinfo/dev-tech-js-engine-internals
>

Steve Fink

unread,
Jun 20, 2013, 1:24:28 PM6/20/13
to Till Schneidereit, JS Internals list
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.

Steve Fink

unread,
Jun 20, 2013, 1:24:28 PM6/20/13
to Till Schneidereit, JS Internals list
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.

Brendan Eich

unread,
Jun 20, 2013, 2:12:46 PM6/20/13
to Bobby Holley, JS Internals list, Till Schneidereit
+1, FWIW. Templates as implementation detail should be abstracted using
typedefs. Even templates as API can use typedef shorthanding -- it's a
form of B&D programming to make all consumers spell out the long-hand
just to be over-concrete, or pay homage to C++.

/be

Bobby Holley wrote:
> I like the typedefs myself. But more fundamentally, I believe pretty
> strongly that we should do the same thing in and outside of the JS engine
> (so that, in particular, JS hackers are eating their own dogfood). I've
> mandated this by fiat in XPConnect, but also believe that the current
> mandate of "typedefs in the engine, templates in the browser" is
> undesirable.
>
> Using the templates in the browser is particularly crappy because browser
> code generally doesn't |using namespace JS|. So you end up having to
> namespace-qualify twice: JS::MutableHandle<JS::Value>
>
> bholley
>
>
> On Thu, Jun 20, 2013 at 7:21 AM, Till Schneidereit
> <tschne...@gmail.com>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.
>>
>> 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?
>>
>> 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.
>>
>>

Steve Fink

unread,
Jun 20, 2013, 2:27:58 PM6/20/13
to Brendan Eich, Bobby Holley, Till Schneidereit, JS Internals list
Then the question becomes whether in this case the templates are an
implementation detail or a useful part of the type. bz has code that
makes use of the fact that they're templates. It sounds like our marking
code does something similar. Both of those imply that it is an aspect of
the types that is relevant to users, not just an implementation detail.

I suppose you could argue that you could use both, typedefs by default
and templates only when you need them. But having both means people
always have to decide which to use, which feels to me like unnecessary
API friction.

Bobby Holley

unread,
Jun 20, 2013, 2:36:39 PM6/20/13
to Steve Fink, Till Schneidereit, Brendan Eich, JS Internals list
On Thu, Jun 20, 2013 at 11:27 AM, Steve Fink <sf...@mozilla.com> wrote:

> I suppose you could argue that you could use both, typedefs by default and
> templates only when you need them. But having both means people always have
> to decide which to use, which feels to me like unnecessary API friction.


I disagree. I think we could pretty easily promote the typedefs, which will
get used anyway because they're easier, and let people with special needs
to the more verbose thing. This seems like a perfectly workable solution to
me.

Jeff Walden

unread,
Jun 20, 2013, 8:31:29 PM6/20/13
to
On 06/20/2013 11:36 AM, Bobby Holley wrote:> I think we could pretty easily promote the typedefs, which will
> get used anyway because they're easier

I think that's debatable. The typedefs are (negligibly) easier to *type*. But they are not easier to understand. Extra abstraction layers obfuscate, because looking at the implementation of them requires unwrapping through the typedef first. That extra type-chasing hurts, even if you get used to it.

typedefs also may lead people into thinking that those "types" can be forward-declared, leading to nasty little surprises when someone tries it. And there's the issue that typedefs hide the underlying type. If I have Rooted<JSString*>, it's clear that trying to seriously use that requires I have the definition of JSString. But if I have RootedString, the implication about what definition is needed to meaningfully use it is much less clear.

Jeff

Nicholas Nethercote

unread,
Jun 20, 2013, 11:00:05 PM6/20/13
to Bobby Holley, Steve Fink, JS Internals list, Brendan Eich, Till Schneidereit
I agree that doing the same thing inside and outside SpiderMonkey is preferable.

I slightly favour using typedefs, to minimize keystrokes. For the
weird bz case he can use explicit template syntax.

Nick

Nicholas Nethercote

unread,
Jun 20, 2013, 11:00:05 PM6/20/13
to Bobby Holley, Steve Fink, JS Internals list, Brendan Eich, Till Schneidereit

Jim Blandy

unread,
Jun 21, 2013, 2:54:28 AM6/21/13
to dev-tech-js-en...@lists.mozilla.org
I definitely prefer not using the typedefs. Reading is more important
than writing, and the typedefs introduce an extra level of indirection:
"What is HandleString, exactly, again?" It's really nice to see
Handle<JSObject *> and not have to ask further questions. And the
typedefs are not significantly shorter, visually.

If there isn't a consensus, this is the kind of decision a maintainer
could make, if it's really an issue at all.

Jim Blandy

unread,
Jun 21, 2013, 2:59:22 AM6/21/13
to dev-tech-js-en...@lists.mozilla.org
I'm surprised people are offering justifications based on how much work
it is to type or add typedefs or whatever. Reading is *vastly* more
common than writing; that's the case to optimize for.

I don't agree that the templates are an implementation detail:

1) All the template instantiations support the same interface. When you
see a Rooted<T>, you know exactly what it does. Not so with typedefs.

2) I can define my own templates ranging over the set of types that
Handle, Rooted, etc. support, and use Handle<T>.

Bobby Holley

unread,
Jun 21, 2013, 12:06:44 PM6/21/13
to Jim Blandy, JS Internals list
On Thu, Jun 20, 2013 at 11:59 PM, Jim Blandy <ji...@mozilla.com> wrote:

> 1) All the template instantiations support the same interface. When you
> see a Rooted<T>, you know exactly what it does. Not so with typedefs.
>

That seems like something we can quite easily establish by convention.

Are you concerned about the difference indirection levels (HandleValue =>
Handle<Value> whereas HandleObject => Handle<JSObject*>)? I don't think
that's actually an issue for most consumers. Most people want, quite
literally, "A Handle to A Foo". The level of pointer indirection involved
is exactly the kind of implementation detail that we should abstract away.


> 2) I can define my own templates ranging over the set of types that
> Handle, Rooted, etc. support, and use Handle<T>.
>

As noted earlier in the thread, there's no reason we can't expose the
templated versions for people doing specialized stuff. But That's probably
< 5% of the total consumers.

bholley

Brendan Eich

unread,
Jun 21, 2013, 3:24:16 PM6/21/13
to Jim Blandy, dev-tech-js-en...@lists.mozilla.org
Jim Blandy wrote:
> I'm surprised people are offering justifications based on how much work
> it is to type or add typedefs or whatever.

I think readability can favor typedefs too, though, and tried to say
that. Sorry for being unclear about "consumers". Readers do not benefit
indefinitely (for every occurrence, say hundreds to thousands in a
source file) from using exclusively long-hands, even ignoring costs to
writers. Good code can even use a "local typedef" to avoid mindless
repetition.

> Reading is *vastly* more
> common than writing; that's the case to optimize for.

Is it optimal to read Handle<T> or Handle<T*> (or Handle<JST*>) spelling
instead of HandleT? In some cases, the template spelling is better.

'typedef' comes from C, where it was used for short-handing, even hiding
pointer declarator modes (e.g., function pointer types -- blame C for
over-parenthesizing and adding other confusion there, but it's loosely
analogous to the present situation).

'typedef' is a two-edged weapon. You can certainly overdo it and hurt
someone. But it can help too, even considering only readability, even
considering only template typedefs -- IMHO.

/be

Nicholas Nethercote

unread,
Jun 21, 2013, 5:35:40 PM6/21/13
to Brendan Eich, Jim Blandy, dev-tech-js-en...@lists.mozilla.org
On Sat, Jun 22, 2013 at 5:24 AM, Brendan Eich <bre...@mozilla.com> wrote:
>
> I think readability can favor typedefs too, though, and tried to say that.
> Sorry for being unclear about "consumers". Readers do not benefit
> indefinitely (for every occurrence, say hundreds to thousands in a source
> file) from using exclusively long-hands, even ignoring costs to writers.
> Good code can even use a "local typedef" to avoid mindless repetition.

+1

Huffman encoding is a good rule of thumb for names -- common names
should be short. And something that is more readable to a complete
newcomer can be less readable to someone with some familiarity.

Nick

Nicholas Nethercote

unread,
Aug 22, 2013, 9:06:56 PM8/22/13
to Till Schneidereit, JS Internals list
On Thu, Jun 20, 2013 at 7:21 AM, Till Schneidereit
<tschne...@gmail.com> wrote:
>
> We still don't have a clear line on how to name handles, both in- and
> outside of the engine.
>
> 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

This thread died, unresolved. We basically need Luke, as module
owner, to make a decision.

I can offer one new data point. I've been working on jsapi.h include
minimization (bug 908050). That's pushed me into the option 1 camp,
because having to deal with the typedefs complicates things -- i.e.
forward declarations for Handle<T> aren't enough; you have to include
js/RootingAPI.h everywhere as well.

Nick

Luke Wagner

unread,
Aug 22, 2013, 11:26:27 PM8/22/13
to Nicholas Nethercote, JS Internals list, Till Schneidereit
> I can offer one new data point. I've been working on jsapi.h include
> minimization (bug 908050). That's pushed me into the option 1 camp,
> because having to deal with the typedefs complicates things -- i.e.
> forward declarations for Handle<T> aren't enough; you have to include
> js/RootingAPI.h everywhere as well.

Just so I understand, was your goal to remove the #include "RootingAPI.h" from jsapi.h and was the problem you had the inability to forward-declare a typedef, or was there more too it?

Thanks,
Luke

Nicholas Nethercote

unread,
Aug 23, 2013, 12:21:29 AM8/23/13
to Luke Wagner, JS Internals list, Till Schneidereit
On Thu, Aug 22, 2013 at 8:26 PM, Luke Wagner <lu...@mozilla.com> wrote:
>
> Just so I understand, was your goal to remove the #include "RootingAPI.h" from jsapi.h and was the problem you had the inability to forward-declare a typedef, or was there more too it?

Not quite. The problem is that some code outside SpiderMonkey
currently uses, for example, |HandleValue|, which requires including
js/RootingAPI.h. Whereas if I change it to |Handle<Value>| I can get
by with just forward declarations of |Handle| and |Value| and don't
need to include any headers. So, outside of SpiderMonkey, the
non-typedef version is definitely preferable.

Nick

Luke Wagner

unread,
Aug 23, 2013, 12:32:29 PM8/23/13
to JS Internals list
I see several aesthetic/ergonomic reasons to prefer using typedefs everywhere, inside and outside the engine:

- When we are not in namespace js or JS, I think everyone should be able to agree that JS::Handle<JS::Value> is definitely too verbose. (We have this problem in SM headers too.)

- It is the general SM and, more broadly, C++ style to immediately typedef any template-id that has more than a few (or even one) use, even for short template-ids. Perhaps for this reason the < > look noisy to my eyes when reading code, like someone should have refactored it to use a typedef.

- Longer typenames are more annoying to type. I know, we read 100x more than write, but we write *a lot* of HandleFoo and I don't see the argument that they are harder to read, as discussed below.

- Longer typenames cause function declarations to wrap to multiple lines which look mildly sloppier (and we have tons of Handles in signatures).

- Super-common names get shortened (take 'cx', 'rt' or, back in the day, 'fp') and Handles are super-common. I'd even be happy to see HandleObj/HandleStr, but I won't push my luck :)

Since these are only aesthetics, a good meaty counter-argument would trump them, but I just don't see it:

- Of course we'll continue to have the templates in the headers (we kinda have to), so the 1% generic programming Handle<T> use case will continue to work.

- On the "Handle<JSObject*> is more explicit / easier to understand / one less indirection" argument, I think we need to consider the cases of programmer using handles:
A. The programmer already understands SM handles: this argument doesn't apply.
B. The programmer is new to GC and handles: finding the definition is the least hard thing (ctags or mxr will take you there immediately); it's not like JS::Handle is some simple template utility that can be easily understood from it's interface. Oh no no, it's all SFINAE and CRTP and template specialization and the only way you are going to know what to do with it is to read the big beefy comment at the top of that file and/or look at some other code using Handles/Rooteds. Any indirection introduced by the typedef is insignificant in the overall process of learning how to correctly use handles, and then, once you have, you're in case A.
C. The programmer is familiar with a different GC handle syntax, say V8s: this is a bit unfortunate, but I expect this set of people is small (and I assume figuring it out will take all of 5 minutes).

- The you-can't-forward-declare-typedefs problem. I think we can address this as Brendan pointed out by forward declaring Handle and putting the HandleX typedefs in jspubtd.h (perhaps with a comment above saying "See js/public/RootingAPI.h").

Lastly, I don't see a good reason to have SM-internal Handle style differ from the mozilla-wide style. I think two different styles would, if anything, hurt understandability for mozilla hackers venturing into SM code. Also, as bholley pointed out, the JS::Handle<JS::Value> situation is worse.

Does anyone see any flagrant misunderstandings or omissions in the above reasoning? If not, it would, as Till originally pointed out, be really good to have a single unified style, and I'd like the typedefs to be that style (except in cases of metaprogrammatic use of Handle<T>).

Cheers,
Luke

----- Original Message -----
> On Thu, Jun 20, 2013 at 7:21 AM, Till Schneidereit
> <tschne...@gmail.com> wrote:
> >
> > We still don't have a clear line on how to name handles, both in- and
> > outside of the engine.
> >
> > 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
>
> This thread died, unresolved. We basically need Luke, as module
> owner, to make a decision.
>
> I can offer one new data point. I've been working on jsapi.h include
> minimization (bug 908050). That's pushed me into the option 1 camp,
> because having to deal with the typedefs complicates things -- i.e.
> forward declarations for Handle<T> aren't enough; you have to include
> js/RootingAPI.h everywhere as well.
>
> Nick

Nicholas Nethercote

unread,
Aug 23, 2013, 5:27:02 PM8/23/13
to Luke Wagner, JS Internals list
On Sat, Aug 24, 2013 at 2:32 AM, Luke Wagner <lu...@mozilla.com> wrote:
>
> - The you-can't-forward-declare-typedefs problem. I think we can address this as Brendan pointed out by forward declaring Handle and putting the HandleX typedefs in jspubtd.h (perhaps with a comment above saying "See js/public/RootingAPI.h").

jspubtd.h is now pretty big for a "include this everywhere" file. It
forward declares lots of types, defines quite a few more, and even has
a few inline method definitions. And we're moving away from
monolithic headers -- goodbye jsapi.h, hello js/*.h -- and jspubtd.h
falls in that tradition.

The good news is that 98% of Gecko's needs would be met by a new file
of this type that only contained the following forward declarations
and typedefs:
- Definitely: JSContext, JSObject, Value, Handle, MutableHandle,
HandleValue, MutableHandleValue
- Maybe: JSString, jsid, Rooted, and all remaining Rooted/Handle +
JSObject/JSString/jsid combinations.

So yes, this could be done.

Nick

Jim Blandy

unread,
Aug 26, 2013, 11:59:05 AM8/26/13
to dev-tech-js-en...@lists.mozilla.org
If I ever *objected* to the typedefs, then that might have been
"argument creep", in which one starts by simply trying to explain a
position and then days later is surprised to find oneself arguing for it
vociferously. I only really meant to say that:
- I slightly prefer to see the structure of "Handle<Value>" over
"HandleValue", and
- it irritates me when people define typedefs for trivial things.

I completely agree that JS::Handle<JS::Value> is irritating and
unacceptable. That's too much noise.

On 08/23/2013 09:32 AM, Luke Wagner wrote:
> I see several aesthetic/ergonomic reasons to prefer using typedefs everywhere, inside and outside the engine:
>
> - When we are not in namespace js or JS, I think everyone should be able to agree that JS::Handle<JS::Value> is definitely too verbose. (We have this problem in SM headers too.)
>
> - It is the general SM and, more broadly, C++ style to immediately typedef any template-id that has more than a few (or even one) use, even for short template-ids. Perhaps for this reason the < > look noisy to my eyes when reading code, like someone should have refactored it to use a typedef.
>
> - Longer typenames are more annoying to type. I know, we read 100x more than write, but we write *a lot* of HandleFoo and I don't see the argument that they are harder to read, as discussed below.
>
> - Longer typenames cause function declarations to wrap to multiple lines which look mildly sloppier (and we have tons of Handles in signatures).
>
> - Super-common names get shortened (take 'cx', 'rt' or, back in the day, 'fp') and Handles are super-common. I'd even be happy to see HandleObj/HandleStr, but I won't push my luck :)
>
> Since these are only aesthetics, a good meaty counter-argument would trump them, but I just don't see it:
>
> - Of course we'll continue to have the templates in the headers (we kinda have to), so the 1% generic programming Handle<T> use case will continue to work.
>
> - On the "Handle<JSObject*> is more explicit / easier to understand / one less indirection" argument, I think we need to consider the cases of programmer using handles:
> A. The programmer already understands SM handles: this argument doesn't apply.
> B. The programmer is new to GC and handles: finding the definition is the least hard thing (ctags or mxr will take you there immediately); it's not like JS::Handle is some simple template utility that can be easily understood from it's interface. Oh no no, it's all SFINAE and CRTP and template specialization and the only way you are going to know what to do with it is to read the big beefy comment at the top of that file and/or look at some other code using Handles/Rooteds. Any indirection introduced by the typedef is insignificant in the overall process of learning how to correctly use handles, and then, once you have, you're in case A.
> C. The programmer is familiar with a different GC handle syntax, say V8s: this is a bit unfortunate, but I expect this set of people is small (and I assume figuring it out will take all of 5 minutes).
>
> - The you-can't-forward-declare-typedefs problem. I think we can address this as Brendan pointed out by forward declaring Handle and putting the HandleX typedefs in jspubtd.h (perhaps with a comment above saying "See js/public/RootingAPI.h").
>

Steve Fink

unread,
Aug 26, 2013, 1:30:59 PM8/26/13
to Jim Blandy, dev-tech-js-en...@lists.mozilla.org
I would have still preferred the explicit Handle<T> notation, but not
enough to argue the point. I'd rather have the matter settled.

To recap my arguments, for no particular reason:

- The main choice between template vs typedef is whether the information
being hidden is relevant or not. To me, the fact that Handle<T> has
roughly the same relationship to T for all T *is* relevant (because of
the particular relationship, not in general). HandleObject and
HandleValue could be two entirely different types. Handle<T> enables you
to read it as "pointer to a rooted T", at which point much of the
confusion over how this stuff works drops away.

- Handle<T> feels like introducing one new type. HandleObject,
HandleValue, HandleScript, etc. feels like introducing a dozen.

- Handle<T> feels more hackable. It tells you that you can add stuff to
all of these types at once by adding stuff to Handle, and of course that
you can use template instantation to get the appropriate Handle type
when needed.

- Forward declaration is easier

And my counter to the arguments for the typedefs:

- JS::Handle<JS::Value> is indeed ugly. But you can't compare to
HandleValue; it'd still be JS::HandleValue. It sounds like people aren't
crazy about 'using namespace JS' or 'using JS::Value', so it's probably
"JS::Handle<JS::Value> vs JS::HandleValue" or "Handle<JS::Value> vs
HandleValue". A difference, but not a huge one.

- Luke's breakdown of cases of different programmers' understanding of
handles is a little oversimplified. The set of programmers who already
understand Handles is pretty close to the empty set, or at least it
oscillates between the empty set and something very small. I mostly
understand handles, but keep forgetting the details. And I've mentally
tried out several different ways of thinking about them before settling
on "pointer to rooted T".

Luke's category B argument, though, makes sense -- knowing that
HandleValue is a templatized Handle<Value> doesn't get you very far in
understand that specific specialization. And it isn't the only
specialization that differs from the default. That's the strongest
argument in favor of the typedefs in my mind.

Ok, got that off my chest. I'm done now. :-)

Oh, wait, not quite. What's the policy on Rooted and Handle types within
.cpp files, for one-offs or rarely-used types? We have a number of
these, mostly for Rooted, and it seems weird to use a local typedef when
you're probably only using it to avoid losing type information in the
first place (eg using a Handle<JSLinearString*> instead of a
HandleString because the callee wants to know it's dealing with a
JSLinearString.) Is it mandatory to use a typedef to match the standard
style? Encouraged? Discouraged? I guess it's ok to leave it to the coder
and reviewer, but we already know that this is an area with widely
divergent opinions on aesthetic gut-feel...

% egrep 'typedef Handle<' **/*.cpp
frontend/Parser.cpp:typedef Handle<StaticBlockObject*>
HandleStaticBlockObject;
jsstr.cpp:typedef Handle<JSLinearString*> HandleLinearString;
% egrep 'typedef.*Rooted<' **/*.cpp
ctypes/Library.cpp:typedef Rooted<JSFlatString*> RootedFlatString;
frontend/Parser.cpp:typedef Rooted<StaticBlockObject*>
RootedStaticBlockObject;
jsiter.cpp:typedef Rooted<PropertyIteratorObject*>
RootedPropertyIteratorObject;
jsscript.cpp:typedef Rooted<GlobalObject *> RootedGlobalObject;
vm/ScopeObject.cpp:typedef Rooted<ArgumentsObject *> RootedArgumentsObject;

Luke Wagner

unread,
Aug 26, 2013, 1:54:20 PM8/26/13
to Steve Fink, Jim Blandy, dev-tech-js-en...@lists.mozilla.org
> Oh, wait, not quite. What's the policy on Rooted and Handle types within
> .cpp files, for one-offs or rarely-used types? We have a number of
> these, mostly for Rooted, and it seems weird to use a local typedef when
> you're probably only using it to avoid losing type information in the
> first place (eg using a Handle<JSLinearString*> instead of a
> HandleString because the callee wants to know it's dealing with a
> JSLinearString.) Is it mandatory to use a typedef to match the standard
> style? Encouraged? Discouraged? I guess it's ok to leave it to the coder
> and reviewer, but we already know that this is an area with widely
> divergent opinions on aesthetic gut-feel...

typedef'ing every single one seems like overkill but if there are more than 2 or 3 uses of a given Handle/Rooted template-id, then I think it does make sense to add a typedef for consistency. E.g., I can see that there is already a local HandlePropertyName in the frontend for this reason. Throwing away type information (HandleLinearString -> HandleString) shouldn't be necessary and the regularity of the HandleX naming scheme shouldn't increase anyone's cognitive burden.

> The set of programmers who already
> understand Handles is pretty close to the empty set, or at least it
> oscillates between the empty set and something very small.

It should include most SM and JS-touching Gecko hackers by now. Unless you using some deep-grokking definition of 'understand', but I don't think that definition makes sense to use in this context.

Jeff Walden

unread,
Aug 30, 2013, 4:16:37 PM8/30/13
to Steve Fink, Jim Blandy, dev-tech-js-en...@lists.mozilla.org
On 08/26/2013 10:30 AM, Steve Fink wrote:
> - JS::Handle<JS::Value> is indeed ugly. But you can't compare to
> HandleValue; it'd still be JS::HandleValue. It sounds like people aren't
> crazy about 'using namespace JS' or 'using JS::Value', so it's probably
> "JS::Handle<JS::Value> vs JS::HandleValue" or "Handle<JS::Value> vs
> HandleValue". A difference, but not a huge one.

Why exactly are people unwilling to use |using JS::Value|? Opening the whole namespace is understandably bad. But I've never heard anyone say why narrowly-scoped |using| statements are unacceptable.

Jeff

Boris Zbarsky

unread,
Aug 30, 2013, 5:27:18 PM8/30/13
to
On 8/30/13 4:16 PM, Jeff Walden wrote:
> On 08/26/2013 10:30 AM, Steve Fink wrote:
>> - JS::Handle<JS::Value> is indeed ugly. But you can't compare to
>> HandleValue; it'd still be JS::HandleValue. It sounds like people aren't
>> crazy about 'using namespace JS' or 'using JS::Value', so it's probably
>> "JS::Handle<JS::Value> vs JS::HandleValue" or "Handle<JS::Value> vs
>> HandleValue". A difference, but not a huge one.
>
> Why exactly are people unwilling to use |using JS::Value|?

It's too generic a name. Especially for headers.

Offhand, we have at least two other classes named Value, in different
namespaces, in our codebase.

Would nsStyleAnimation.cpp still compile if Element.h had "using
JS::Value" for the functions it declares that take that type?

-Boris
0 new messages