www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Eponymous template with full template syntax

reply =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
I think main's second line used to work:

template isSmall(T)
{
     enum isSmall = (T.sizeof < 12345);
}

void main()
{
     static assert(isSmall!int);          // <-- the usual syntax works

     static assert(isSmall!int.isSmall);  // <-- compilation ERROR
}

Error: template deneme.isSmall does not match any function template 
declaration. Candidates are:
        deneme.isSmall(T)
Error: template deneme.isSmall(T) cannot deduce template function from 
argument types !()(bool)

Am I imagining it? I don't have a problem with it. :) Was the change 
intentional?

Ali
Jul 01 2013
next sibling parent "Jonathan M Davis" <jmdavisProg gmx.com> writes:
On Monday, July 01, 2013 11:15:04 Ali Çehreli wrote:
 I think main's second line used to work:
 
 template isSmall(T)
 {
 enum isSmall = (T.sizeof < 12345);
 }
 
 void main()
 {
 static assert(isSmall!int); // <-- the usual syntax works
 
 static assert(isSmall!int.isSmall); // <-- compilation ERROR
 }
 
 Error: template deneme.isSmall does not match any function template
 declaration. Candidates are:
 deneme.isSmall(T)
 Error: template deneme.isSmall(T) cannot deduce template function from
 argument types !()(bool)
 
 Am I imagining it? I don't have a problem with it. :) Was the change
 intentional?
I'm not aware of it ever having worked, but given that the whole point of eponymous templates is that they be replaced with the symbol carrying their name and _everything_ else in the template is hidden, I would think that what you're seeing is correct behavior. isSmall!int is replaced with the isSmall within isSmall!int, and isSmall.isSmall makes no sense, so if that was allowed before, I'd definitely argue that disallowing it was a bug fix. - Jonathan m Davis
Jul 01 2013
prev sibling next sibling parent reply "Maxim Fomin" <maxim maxim-fomin.ru> writes:
On Monday, 1 July 2013 at 18:15:06 UTC, Ali Çehreli wrote:
 I think main's second line used to work:

 template isSmall(T)
 {
     enum isSmall = (T.sizeof < 12345);
 }

 void main()
 {
     static assert(isSmall!int);          // <-- the usual 
 syntax works

     static assert(isSmall!int.isSmall);  // <-- compilation 
 ERROR
 }

 Error: template deneme.isSmall does not match any function 
 template declaration. Candidates are:
        deneme.isSmall(T)
 Error: template deneme.isSmall(T) cannot deduce template 
 function from argument types !()(bool)

 Am I imagining it? I don't have a problem with it. :) Was the 
 change intentional?

 Ali
I think that this probably worked as early as in the end of 2011 but I can be wrong as don't remember exactly. It seems that dmd recognizes isSmall!int.isSmall as potential UFCS property, converts isSmall!int to bool and tries to issue call isSmall(bool) and fails, because that template does not define any function.
Jul 01 2013
parent reply =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 07/01/2013 12:03 PM, Maxim Fomin wrote:

 I think that this probably worked as early as in the end of 2011 but I
 can be wrong as don't remember exactly.
To answer Jonathan's question as well, it must have worked because I see it in code that is definitely tested when it was written.
 It seems that dmd recognizes isSmall!int.isSmall as potential UFCS
 property, converts isSmall!int to bool and tries to issue call
 isSmall(bool) and fails, because that template does not define any
 function.
That explains it. :) Let's play with it a little: import std.stdio; template isSmall(T) { enum isSmall = (T.sizeof < 12345); struct S { T m; } } struct S { int[10] i; } void main() { writeln(isSmall!int); writeln(isSmall!int.S.init); writeln(isSmall!int.S); } First of all, apparently a template can include a definition with the same name but I still cannot type isSmall!int.isSmall. I guess the above is still an eponymous template and isSmall!int still means isSmall!int.isSmall. Now guess what the last two lines print. :) isSmall!int.S is *not* the S that is included in the template! Here is the output: true S([0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) S([1, 1, 1, 1, 1, 1, 1, 1, 1, 1]) The last line is actually an anonymous struct object of type S (the S that is defined at module level). That is confusing. Ali
Jul 01 2013
parent reply "monarch_dodra" <monarchdodra gmail.com> writes:
On Monday, 1 July 2013 at 20:28:28 UTC, Ali Çehreli wrote:
 On 07/01/2013 12:03 PM, Maxim Fomin wrote:

 I think that this probably worked as early as in the end of
2011 but I
 can be wrong as don't remember exactly.
To answer Jonathan's question as well, it must have worked because I see it in code that is definitely tested when it was written.
 It seems that dmd recognizes isSmall!int.isSmall as potential
UFCS
 property, converts isSmall!int to bool and tries to issue call
 isSmall(bool) and fails, because that template does not
define any
 function.
That explains it. :) Let's play with it a little: import std.stdio; template isSmall(T) { enum isSmall = (T.sizeof < 12345); struct S { T m; } } struct S { int[10] i; } void main() { writeln(isSmall!int); writeln(isSmall!int.S.init); writeln(isSmall!int.S); } First of all, apparently a template can include a definition with the same name but I still cannot type isSmall!int.isSmall. I guess the above is still an eponymous template and isSmall!int still means isSmall!int.isSmall. Now guess what the last two lines print. :) isSmall!int.S is *not* the S that is included in the template! Here is the output: true S([0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) S([1, 1, 1, 1, 1, 1, 1, 1, 1, 1]) The last line is actually an anonymous struct object of type S (the S that is defined at module level).
I though UFCS wasn't possible with constructors? *That* very usecase is one of the reasons why. Shouldn't that be an accepts-invalid?
 That is confusing.
UFCS construction: Yes. The rest, not so much: The idea is that once a template is "eponymous", it *fully* becomes the eponymous function/type/value (s). Every other function, regardless of public/private*, simply seizes to exist to the outside world. You can't make a "qualified" call to an eponymous template, because the "qualification" is already the call. Long story short, it's not mix and match: Either you have a normal template, or you have an something eponymous, not a bit of both: *What qualifies for eponymous template is kind of "buggy", since what actually qualifies is not exactly what the spec says. Still, *once* something is considered "qualified" by the implementation, then it is fully eponymous.
Jul 01 2013
parent reply =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 07/01/2013 02:10 PM, monarch_dodra wrote:

 That is confusing.
UFCS construction: Yes.
I *think* I did not know it but I can't be sure. :) struct S { int i; } void main() { static assert (S(42) == 42.S); } It works with 2.063 (v2.064-devel-a1a1537 too).
 The rest, not so much:

 The idea is that once a template is "eponymous", it *fully* becomes the
 eponymous function/type/value (s). Every other function, regardless of
 public/private*, simply seizes to exist to the outside world. You can't
 make a "qualified" call to an eponymous template, because the
 "qualification" is already the call.
A single definition with the same name makes it an eponymous template. I used to think that the template should also have a single definition. So, currently other definitions act as implementation details of the template. The following template sees the local S, not the module-level one: struct S { int[10] i; } template epo(T) { size_t epo() { return S.sizeof; // <-- epo.S, not .S } struct S { int i; } double foo() { return 1.5; } } void main() { assert(epo!int() == int.sizeof); // <-- yes, epo.S mixin epo!int; assert(foo() == 1.5); } Also note that mixing in the template is still possible but it is an orthogonal feature anyway. Ali
Jul 01 2013
parent "monarch_dodra" <monarchdodra gmail.com> writes:
On Monday, 1 July 2013 at 22:46:55 UTC, Ali Çehreli wrote:
 On 07/01/2013 02:10 PM, monarch_dodra wrote:

 That is confusing.
UFCS construction: Yes.
I *think* I did not know it but I can't be sure. :)
AH... I looked at the threads some more: I was actually thinking about a proposal that wanted (just like UFCS), to allow non-intrusively adding constructors. So I guess UFCS and constructors are fair game? I do not like this at all...
Jul 01 2013
prev sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Mon, 01 Jul 2013 14:15:04 -0400, Ali =C3=87ehreli <acehreli yahoo.com=
 wrote:
 I think main's second line used to work:

 template isSmall(T)
 {
      enum isSmall =3D (T.sizeof < 12345);
 }

 void main()
 {
      static assert(isSmall!int);          // <-- the usual syntax work=
s
      static assert(isSmall!int.isSmall);  // <-- compilation ERROR
 }

 Error: template deneme.isSmall does not match any function template  =
 declaration. Candidates are:
         deneme.isSmall(T)
 Error: template deneme.isSmall(T) cannot deduce template function from=
=
 argument types !()(bool)

 Am I imagining it? I don't have a problem with it. :) Was the change  =
 intentional?
I think it used to work, and I think the change was intentional. I also= = "discovered" this not too long ago. -Steve
Jul 01 2013