Re: Extended attributes vs. new types

On 1/12/17 2:23 PM, Domenic Denicola wrote:
> And if we end up wanting to capture the by-reference vs. by-copy semantics in the type system

Right, at that point we're sort of off into multiple orthogonal 
annotations: copy/reference semantics and allow/disallow sharing...

> One of the big things your message drove home is how extended attributes apply to syntactic productions like dictionary members, attributes, methods, interfaces, etc. and not to types.

Hmm.  That's a good point.

In particular, the obvious corollary is that we can't just redefine 
Type, syntactically, to include extended attributes, because then this:

   void foo([SomeAttr] int arg);

would be syntactically ambiguous.

But what we could do is have a TypeWithAttributes which is defined as 
"ExtendedAttributeList Type"  We could use TypeWithAttributes in almost 
all places where an ES-to-IDL conversion would be involved, except where 
a grammar production that can be preceded by ExtendedAttributeList can 
start with Type.  Looking through the grammar really quickly, the things 
that involve ES-to-IDL conversions and can start with Type would be 
OptionalOrRequiredArgument and DictionaryMember.  For those we could 
specify that certain extended attributes specified on the argument or 
dictionary member get propagated to its type instead.  In other places 
we'd use TypeWithAttributes instead of Type.

Note that in looking through this stuff just now I found two places that 
would need "threading through" that I had missed initially: setlike<V> 
and maplike<K,V> where you want to specify whether V can be a 
shared/clamped/whatever thing or not...

Anyway, there would need to be a bit of careful handling of cases like this:

   typedef [Clamp] long ClampedLong;

   void foo([EnforceRange] ClampedLong arg);

which should error out, because fundamentally both the [Clamp] and the 
[EnforceRange] are being stuck on the "long", right?

There will be this weird inconsistency where you write:

   dictionary Dict {
     [Clamp] required long member;
   };

and

   interface Iface {
     void foo([Clamp] optional long arg);
   };

vs

   interface Iface {
     attribute [Clamp] long attr;
   };

but maybe we can rejigger dictionary required member grammar and 
operation optional arg grammar so the case when the keyword ("required" 
or "optional") is present is more separate (and followed by 
TypeWithAttributes) and the case when the keyword is absent starts with 
Type and propagates extended attrs.  Then this:

   interface Iface {
     void foo([Clamp] long arg);
   };

would quack very similarly to this:

   interface Iface {
     void foo(optional [Clamp] long arg);
   };

even if the under-the-hood reasons it worked were different.

> I think it would be nice to introduce this concept into the spec, and retrofit it onto those extended attributes, but I'm not sure it's worth the trouble for implementers.

I think the ability to apply the existing extended attrs to things like 
union members, maplike/setlike values, etc, is worth a certain amount of 
trouble.  I don't think it will be _that_ much trouble in practice if we 
do it this way.  Definitely less trouble than threading things through 
conversion code.

> It also comes with questions like---should we invent a new concept and syntax, separate from extended attributes? Or should we say that certain extended attributes apply exclusively to types, just like certain of them apply to attributes/interfaces/etc. I guess that latter option would introduce a dependency from the parser to the semantics; to interpret `void f([X] long foo)` you'd be unsure whether [X] is associated with the parameter or the type until you knew if X was one of the type-only extended attributes.

In terms of the parser it would have to be associated with the argument, 
of course.  But the argument could propagate it through to its type per 
above suggestion.

> (Unless we banned extended attributes on parameters entirely? Are only these type-applicable extended attributes currently used on parameters?)

The extended attributes that currently apply to operation arguments are: 
[Clamp], [EnforceRange], [TreatNullAs].  The first two of those also 
apply to dictionary members, but [TreatNullAs] does not (though there's 
no obvious reason it can't).

> Thoughts? Mainly on the "is it worth it" question, I suppose.

I suspect it probably is...

-Boris

Received on Thursday, 12 January 2017 20:19:33 UTC