Thread overview
Irritating template inconsistency
Apr 20, 2004
Matthew
Apr 21, 2004
Walter
Apr 21, 2004
Derek Parnell
Apr 21, 2004
Walter
Apr 21, 2004
Matthew
Apr 21, 2004
Walter
Apr 21, 2004
Matthew
Apr 21, 2004
Walter
Apr 21, 2004
Matthew
April 20, 2004
D provides for the programmer to omit the type within a template instantiation, if there is only one type in the template, and it has the same name as the template. This is provided as a convenience (AFAIK). Consider the following code:

  template Thing(T)
  {
    class Thing
    {}
  }

  template Thing2(T)
  {
    class Thing2
    {}

    class X
    {}
  }

  int main()
  {
    alias Thing!(int)     thing_int_t;
    alias Thing2!(int).Thing2 thing2_int_t;

    alias Thing!(int).Thing   thing_int_2_t;  // no property 'Thing' for
type 'Thing'

    return 0;
  }

The first instantiation does not require anything after the "!(int)" because there is only one type - the class Thing - within the Thing template.

The second instantiation does require the full qualification, because there are two types within the template.

The third instantiation is an error, and gives a misleading error message. Is this intended behaviour? It seems unnecessarily inconsistent, and is very irritating when one is developing template code and moving things around a lot, as the client code has to be changed every time.



April 21, 2004
"Matthew" <matthew.hat@stlsoft.dot.org> wrote in message news:c63vmm$ju5$1@digitaldaemon.com...
> D provides for the programmer to omit the type within a template instantiation, if there is only one type in the template, and it has the same name as the template. This is provided as a convenience (AFAIK). Consider the following code:
>
>   template Thing(T)
>   {
>     class Thing
>     {}
>   }
>
>   template Thing2(T)
>   {
>     class Thing2
>     {}
>
>     class X
>     {}
>   }
>
>   int main()
>   {
>     alias Thing!(int)     thing_int_t;
>     alias Thing2!(int).Thing2 thing2_int_t;
>
>     alias Thing!(int).Thing   thing_int_2_t;  // no property 'Thing' for
> type 'Thing'
>
>     return 0;
>   }
>
> The first instantiation does not require anything after the "!(int)"
because
> there is only one type - the class Thing - within the Thing template.
>
> The second instantiation does require the full qualification, because
there
> are two types within the template.
>
> The third instantiation is an error, and gives a misleading error message. Is this intended behaviour? It seems unnecessarily inconsistent, and is
very
> irritating when one is developing template code and moving things around a lot, as the client code has to be changed every time.

Yes, it is intended. You can avoid the issue, though, by adding a dummy declaration in the template.


April 21, 2004
On Tue, 20 Apr 2004 17:26:13 -0700, Walter wrote:

> "Matthew" <matthew.hat@stlsoft.dot.org> wrote in message news:c63vmm$ju5$1@digitaldaemon.com...
>> D provides for the programmer to omit the type within a template instantiation, if there is only one type in the template, and it has the same name as the template. This is provided as a convenience (AFAIK). Consider the following code:
>>
>>   template Thing(T)
>>   {
>>     class Thing
>>     {}
>>   }
>>
>>   template Thing2(T)
>>   {
>>     class Thing2
>>     {}
>>
>>     class X
>>     {}
>>   }
>>
>>   int main()
>>   {
>>     alias Thing!(int)     thing_int_t;
>>     alias Thing2!(int).Thing2 thing2_int_t;
>>
>>     alias Thing!(int).Thing   thing_int_2_t;  // no property 'Thing' for
>> type 'Thing'
>>
>>     return 0;
>>   }
>>
>> The first instantiation does not require anything after the "!(int)"
> because
>> there is only one type - the class Thing - within the Thing template.
>>
>> The second instantiation does require the full qualification, because
> there
>> are two types within the template.
>>
>> The third instantiation is an error, and gives a misleading error message. Is this intended behaviour? It seems unnecessarily inconsistent, and is
> very
>> irritating when one is developing template code and moving things around a lot, as the client code has to be changed every time.
> 
> Yes, it is intended. You can avoid the issue, though, by adding a dummy declaration in the template.

Walter,
what is your reason for this behaviour. Not that I'm suggesting anything is
wrong or otherwise, just curious. I guess I'm hoping that it wasn't an
arbitrary or "convenient" decision, but instead one based on sound
reasoning.

-- 
Derek
21/Apr/04 11:02:50 AM
April 21, 2004
"Walter" <walter@digitalmars.com> wrote in message news:c64ffb$1ehd$2@digitaldaemon.com...
>
> "Matthew" <matthew.hat@stlsoft.dot.org> wrote in message news:c63vmm$ju5$1@digitaldaemon.com...
> > D provides for the programmer to omit the type within a template instantiation, if there is only one type in the template, and it has the same name as the template. This is provided as a convenience (AFAIK). Consider the following code:
> >
> >   template Thing(T)
> >   {
> >     class Thing
> >     {}
> >   }
> >
> >   template Thing2(T)
> >   {
> >     class Thing2
> >     {}
> >
> >     class X
> >     {}
> >   }
> >
> >   int main()
> >   {
> >     alias Thing!(int)     thing_int_t;
> >     alias Thing2!(int).Thing2 thing2_int_t;
> >
> >     alias Thing!(int).Thing   thing_int_2_t;  // no property 'Thing' for
> > type 'Thing'
> >
> >     return 0;
> >   }
> >
> > The first instantiation does not require anything after the "!(int)"
> because
> > there is only one type - the class Thing - within the Thing template.
> >
> > The second instantiation does require the full qualification, because
> there
> > are two types within the template.
> >
> > The third instantiation is an error, and gives a misleading error
message.
> > Is this intended behaviour? It seems unnecessarily inconsistent, and is
> very
> > irritating when one is developing template code and moving things around
a
> > lot, as the client code has to be changed every time.
>
> Yes, it is intended. You can avoid the issue, though, by adding a dummy declaration in the template.

What's the rationale? It doesn't make sense to me. And your solution smacks of a C++ hack. Isn't this a modern language designed from the off to avoid crappy hacks?


April 21, 2004
"Derek Parnell" <derek@psych.ward> wrote in message news:13z4hgc9kgxng$.1jahjei5gnd6s$.dlg@40tude.net...
> > Yes, it is intended. You can avoid the issue, though, by adding a dummy declaration in the template.
>
> Walter,
> what is your reason for this behaviour. Not that I'm suggesting anything
is
> wrong or otherwise, just curious. I guess I'm hoping that it wasn't an arbitrary or "convenient" decision, but instead one based on sound reasoning.

The symbol table lookups needed to be unambiguous. Therefore, a rule is required to say in what scope a symbol is in. Having it in both scopes and trying to guess what the programmer meant leads to trouble like the wretched tag name space in C++.

I'd rather have a simple rule that is easilly explained that may lead to minor aggravation on occaision, than a complicated rule that is hard to explain that mostly works right until it doesn't and somebody starts up a "D Bug of the Month" column <g>.


April 21, 2004
"Matthew" <matthew.hat@stlsoft.dot.org> wrote in message news:c64i8l$1j2g$2@digitaldaemon.com...
> What's the rationale? It doesn't make sense to me. And your solution
smacks
> of a C++ hack. Isn't this a modern language designed from the off to avoid crappy hacks?

It's a worse hack to have the symbol appear in two scopes. Consider:

template Foo(T)
{
    class Foo
    {
        int Foo;
    }
}

Now we do:

    Foo!(int).Foo

What are we referring to? class Foo or int Foo?


April 21, 2004
"Walter" <walter@digitalmars.com> wrote in message news:c65dof$314c$2@digitaldaemon.com...
>
> "Matthew" <matthew.hat@stlsoft.dot.org> wrote in message news:c64i8l$1j2g$2@digitaldaemon.com...
> > What's the rationale? It doesn't make sense to me. And your solution
> smacks
> > of a C++ hack. Isn't this a modern language designed from the off to avoid crappy hacks?
>
> It's a worse hack to have the symbol appear in two scopes. Consider:
>
> template Foo(T)
> {
>     class Foo
>     {
>         int Foo;
>     }
> }
>
> Now we do:
>
>     Foo!(int).Foo
>
> What are we referring to? class Foo or int Foo?

Well, this is where I could comment that we should be using the :: operator ...

I take your point with the given example, but I would then suggest that the short-circuit version be dropped. Since there's still the "!(...)' gunk needed, why not just incline people to use aliases in all cases. I would prefer the consistency, as I'm finding this the most vexing part of my use of templates, and not in the least "minor aggravation on occasion".




April 21, 2004
"Matthew" <matthew.hat@stlsoft.dot.org> wrote in message news:c65enm$129$2@digitaldaemon.com...
> Well, this is where I could comment that we should be using the ::
operator ...
>
> I take your point with the given example, but I would then suggest that
the
> short-circuit version be dropped. Since there's still the "!(...)' gunk
needed,
> why not just incline people to use aliases in all cases. I would prefer
the
> consistency, as I'm finding this the most vexing part of my use of
templates, and
> not in the least "minor aggravation on occasion".

The short circuit version is there because people simply did not like the:

    Foo!(int).Foo

construct for one member templates, and I didn't either.


April 21, 2004
"Walter" <walter@digitalmars.com> wrote in message news:c66f9s$1qqk$2@digitaldaemon.com...
>
> "Matthew" <matthew.hat@stlsoft.dot.org> wrote in message news:c65enm$129$2@digitaldaemon.com...
> > Well, this is where I could comment that we should be using the ::
> operator ...
> >
> > I take your point with the given example, but I would then suggest that
> the
> > short-circuit version be dropped. Since there's still the "!(...)' gunk
> needed,
> > why not just incline people to use aliases in all cases. I would prefer
> the
> > consistency, as I'm finding this the most vexing part of my use of
> templates, and
> > not in the least "minor aggravation on occasion".
>
> The short circuit version is there because people simply did not like the:
>
>     Foo!(int).Foo
>
> construct for one member templates, and I didn't either.

Me either. But I like the inconsistency less. Since alias will be a well-used feature with templates anyway, why not remove the confusing/annoying inconsistency?