Thread overview
Parameter-less templates?
Aug 12, 2013
monarch_dodra
Aug 12, 2013
Jacob Carlborg
Aug 12, 2013
Meta
Aug 13, 2013
deadalnix
Aug 13, 2013
monarch_dodra
Aug 13, 2013
deadalnix
Aug 14, 2013
Tommi
Aug 13, 2013
Kenji Hara
August 12, 2013
D has introduced a pretty cool tool: templates. These are basically namespaces that can be instantiated by a type/alias. Mixing with them the notion of "eponymous" allows to do some seriously cool things with them.

One of the things I find strange though is that they *must* be parameterized. This limitation seems entirely artificial to me. Why not allow templates without parameters, just the same way some functions aren't parameterized. There are useful use-cases for this:
* Simple creation of namespaces (as opposed to non-contructible struct/classes)
* Allows creating private helpers, without polluting the rest of the module (private functions are still callable by other functions in the module).

So... yeah, why don't we have this?

--------

Related: I have encountered this problem, and I can't seem to work around it; *other* than non-parameterized templates. Basically, I have this pred function, we'll call it "foo". This pred function can itself be parameterized to take its own (optional) pred. This basically allows:
foo(a, b)
or
foo!pred(a, b)

This is "traditionally" solved by doing:
void foo(A, B)(A a, B b);
void foo(alias pred, A, B)(A a, B b);

Here is the kicker though: "foo" is itself a pred. This means that I *need* to be able to pass "foo!pred" as a predicate. This does not work, as "foo!pred" is nothing: The compiler doesn't know what you are talking about, as the parameters A and B are missing. This is usually solved by a template:

template foo(alias pred)
{
    void foo(A, B)(A a, B b);
}

This works.... *however* the presence of the "void foo(A, B)(A a, B b);" confuses the crap out of the compiler:
foo(a, b); //OK
alias PRED = foo!"hello";
PRED(a, b); //OK

BUT:
foo!"hello"(a, b); //Error:
Error: template hello.foo does not match any function template declaration. Candidates are:
hello.foo(R1, R2)(R1 r1, R2 r2)
hello.foo(alias pred)
Error: template hello.foo(R1, R2)(R1 r1, R2 r2) cannot deduce template function from argument types !("hello")(int, int)
Error: template instance foo!"hello" errors instantiating template

So... how to make this work? AFAIK, non-parameterized templates should solve it. Or is it just a compiler issue?

FYI: This is a problem present in Phobos. You can use:
"equal!equal(RoR1, RoR2)"
To compare two ranges of ranges. equal!equal gets instanciated, because the args are present to "finish" the missing R1/R2 args after pred.

However, this neat trick stop there:
"equal!(equal!equal)(RoRoR1, RoRoR2)"
This time, this does not work, as the compiler can't resolve the predicate.

I'd like to solve this. IMO "equal!equal" is one of the neatest "1-word" in D, and I want to make sure it works as one would expect it to.

--------

So: Any workaround recommendations? Alternatives? Thoughts on parameter-less templates (regardless of my issue)?
August 12, 2013
On 2013-08-12 21:03, monarch_dodra wrote:
> D has introduced a pretty cool tool: templates. These are basically
> namespaces that can be instantiated by a type/alias. Mixing with them
> the notion of "eponymous" allows to do some seriously cool things with
> them.
>
> One of the things I find strange though is that they *must* be
> parameterized. This limitation seems entirely artificial to me. Why not
> allow templates without parameters, just the same way some functions
> aren't parameterized. There are useful use-cases for this:
> * Simple creation of namespaces (as opposed to non-contructible
> struct/classes)
> * Allows creating private helpers, without polluting the rest of the
> module (private functions are still callable by other functions in the
> module).
>
> So... yeah, why don't we have this?

Do you mean like:

template Foo ()
{
    int a;
}

Unfortunately this doesn't work:

Foo.a = 3;

But this does:

Foo!().a = 3;

-- 
/Jacob Carlborg
August 12, 2013
On Monday, 12 August 2013 at 19:58:32 UTC, Jacob Carlborg wrote:
> Do you mean like:
>
> template Foo ()
> {
>     int a;
> }
>
> Unfortunately this doesn't work:
>
> Foo.a = 3;
>
> But this does:
>
> Foo!().a = 3;

class Foo
{
    static int a;
}

template Foo()
{
    int a = 0;
}

void main()
{
    Foo.a = 0;
}

Wouldn't this be a problem if that syntax was allowed?
August 13, 2013
On Monday, 12 August 2013 at 19:03:41 UTC, monarch_dodra wrote:
> D has introduced a pretty cool tool: templates. These are basically namespaces that can be instantiated by a type/alias. Mixing with them the notion of "eponymous" allows to do some seriously cool things with them.
>
> One of the things I find strange though is that they *must* be parameterized.

Yes and no.

void foo()() {} is a parameter-less template.

As the construct already exists at semantic level, I guess making it available everywhere is the way to go.
August 13, 2013
2013/8/13 monarch_dodra <monarchdodra@gmail.com>

> Related: I have encountered this problem, and I can't seem to work around
> it; *other* than non-parameterized templates. Basically, I have this pred
> function, we'll call it "foo". This pred function can itself be
> parameterized to take its own (optional) pred. This basically allows:
> foo(a, b)
> or
> foo!pred(a, b)
>
> This is "traditionally" solved by doing:
> void foo(A, B)(A a, B b);
> void foo(alias pred, A, B)(A a, B b);
>
> Here is the kicker though: "foo" is itself a pred. This means that I *need* to be able to pass "foo!pred" as a predicate. This does not work, as "foo!pred" is nothing: The compiler doesn't know what you are talking about, as the parameters A and B are missing. This is usually solved by a template:
>
> template foo(alias pred)
> {
>     void foo(A, B)(A a, B b);
> }
>
> This works.... *however* the presence of the "void foo(A, B)(A a, B b);"
> confuses the crap out of the compiler:
> foo(a, b); //OK
> alias PRED = foo!"hello";
> PRED(a, b); //OK
>
> BUT:
> foo!"hello"(a, b); //Error:
> Error: template hello.foo does not match any function template
> declaration. Candidates are:
> hello.foo(R1, R2)(R1 r1, R2 r2)
> hello.foo(alias pred)
> Error: template hello.foo(R1, R2)(R1 r1, R2 r2) cannot deduce template
> function from argument types !("hello")(int, int)
> Error: template instance foo!"hello" errors instantiating template
>
> So... how to make this work? AFAIK, non-parameterized templates should solve it. Or is it just a compiler issue?
>
> FYI: This is a problem present in Phobos. You can use:
> "equal!equal(RoR1, RoR2)"
> To compare two ranges of ranges. equal!equal gets instanciated, because
> the args are present to "finish" the missing R1/R2 args after pred.
>
> However, this neat trick stop there:
> "equal!(equal!equal)(RoRoR1, RoRoR2)"
> This time, this does not work, as the compiler can't resolve the predicate.
>
> I'd like to solve this. IMO "equal!equal" is one of the neatest "1-word" in D, and I want to make sure it works as one would expect it to.
>
> --------
>
> So: Any workaround recommendations? Alternatives? Thoughts on parameter-less templates (regardless of my issue)?
>

Maybe: http://d.puremagic.com/issues/show_bug.cgi?id=10811

Kenji Hara


August 13, 2013
On Tuesday, 13 August 2013 at 01:08:01 UTC, deadalnix wrote:
> On Monday, 12 August 2013 at 19:03:41 UTC, monarch_dodra wrote:
>> D has introduced a pretty cool tool: templates. These are basically namespaces that can be instantiated by a type/alias. Mixing with them the notion of "eponymous" allows to do some seriously cool things with them.
>>
>> One of the things I find strange though is that they *must* be parameterized.
>
> Yes and no.
>
> void foo()() {} is a parameter-less template.
>
> As the construct already exists at semantic level, I guess making it available everywhere is the way to go.

I think strictly speaking, that is a "parameterless parameterized function", as opposed to a "non parameterized function".

In regards to template (I mean the actual "template"), I guess I wish we could either:
1. Allow non-parameterized templates (eg template foo {...})
2. Allow invoking a template without parameters (provided the template has 0 parameters, or default parameters), without doing "!()"

But yeah, I think I agree with you, that it should be made available everywhere.
August 13, 2013
On Tuesday, 13 August 2013 at 09:41:45 UTC, monarch_dodra wrote:
> I think strictly speaking, that is a "parameterless parameterized function", as opposed to a "non parameterized function".
>

No, this is simply syntax sugar on top of eponymous template declaration.

> In regards to template (I mean the actual "template"), I guess I wish we could either:
> 1. Allow non-parameterized templates (eg template foo {...})
> 2. Allow invoking a template without parameters (provided the template has 0 parameters, or default parameters), without doing "!()"
>

Amen !
August 14, 2013
On Tuesday, 13 August 2013 at 09:41:45 UTC, monarch_dodra wrote:
>
> In regards to template (I mean the actual "template"), I guess I wish we could either:
> 1. Allow non-parameterized templates (eg template foo {...})
> 2. Allow invoking a template without parameters (provided the template has 0 parameters, or default parameters), without doing "!()"

I think your proposal no. 1 is good, but there's a problem with your proposal no. 2. This is current D code:

template get(int n = 1)
{
    static if (n == 1) {
        alias get = one;
    }
    else static if (n == 0) {
        enum get = 0;
    }
}

template one(int n)
{
    enum one = 1;
}

template wrap(alias a)
{
    enum wrap = a!0;
}

void main()
{
    static assert(wrap!get == 0);
    static assert(wrap!(get!()) == 1);
}

So, if we go with your proposal no. 2 (allow invoking a template without a parameter list), then the meaning of 'get' in:
wrap!get
...becomes ambiguous. We could be either passing an alias to 'get', or an alias to a parameterless instantiation of template 'get', i.e. get!().