Thread overview
normal function and template function conflict
Jul 26, 2012
monarch_dodra
Jul 26, 2012
Simen Kjaeraas
Jul 26, 2012
monarch_dodra
Jul 26, 2012
Ali Çehreli
Jul 26, 2012
monarch_dodra
Jul 26, 2012
Simen Kjaeraas
Jul 26, 2012
Jacob Carlborg
Jul 26, 2012
Andrej Mitrovic
Jul 26, 2012
Jonathan M Davis
July 26, 2012
I was trying to write a PRNG, and I wanted to give it two seed methods. The first is to seed from a unique UIntType, and the other is to seed from an entire range of seeds. Like so:

--------
void seed(UIntType value = default_seed)
{...}

void seed(Range)(Range range)
  if (isInputRange!Range)
{...}
--------
Where UIntType is a template parameter of the struct.

However, this makes the compiler complain, because of a conflict...? Is mixing normal functions with parametrized ones impossible?

I *fixed* the issue by contemplating the first call with:
--------
void seed(T)(T value = default_seed)
  if (is(typeof(T == UIntType)))
{...}
--------
Problems:
1) It is ugly as sin.
2) The default parameter doesn't work anymore.

So here are my two questions:
1) Is what I was originally trying to do actually illegal, or is it some sort of compiler limitation? TDPL implies this should work perfectly fine...
2) Is there a "correct" workaround?
July 26, 2012
On Thu, 26 Jul 2012 19:18:21 +0200, monarch_dodra <monarchdodra@gmail.com> wrote:

> So here are my two questions:
> 1) Is what I was originally trying to do actually illegal, or is it some sort of compiler limitation? TDPL implies this should work perfectly fine...

Compiler limitation. It's supposed to work.


> 2) Is there a "correct" workaround?

Exactly what you did. Though, for brevity, you would write this:

void seed(T : UIntType)(T value = default_seed)


-- 
Simen
July 26, 2012
On Thursday, 26 July 2012 at 17:57:31 UTC, Simen Kjaeraas wrote:
> On Thu, 26 Jul 2012 19:18:21 +0200, monarch_dodra <monarchdodra@gmail.com> wrote:
>> 2) Is there a "correct" workaround?
>
> Exactly what you did. Though, for brevity, you would write this:
>
> void seed(T : UIntType)(T value = default_seed)

Thanks

I haven't seen this construct before. Can you tell me a bit more
about it, or link me to some documentation about it?

I suppose it means "T must be UIntType", but I'd enjoy having a broader understanding of it :)
July 26, 2012
On 07/26/2012 11:14 AM, monarch_dodra wrote:
> On Thursday, 26 July 2012 at 17:57:31 UTC, Simen Kjaeraas wrote:
>> On Thu, 26 Jul 2012 19:18:21 +0200, monarch_dodra
>> <monarchdodra@gmail.com> wrote:
>>> 2) Is there a "correct" workaround?
>>
>> Exactly what you did. Though, for brevity, you would write this:
>>
>> void seed(T : UIntType)(T value = default_seed)
>
> Thanks
>
> I haven't seen this construct before. Can you tell me a bit more
> about it, or link me to some documentation about it?
>
> I suppose it means "T must be UIntType", but I'd enjoy having a broader
> understanding of it :)

Search for "specialization" in the following resources:

  http://dlang.org/template.html


https://github.com/PhilippeSigaud/D-templates-tutorial/blob/master/dtemplates.pdf

  http://ddili.org/ders/d.en/templates.html

Ali
July 26, 2012
On Thu, 26 Jul 2012 20:14:10 +0200, monarch_dodra <monarchdodra@gmail.com> wrote:

> On Thursday, 26 July 2012 at 17:57:31 UTC, Simen Kjaeraas wrote:
>> On Thu, 26 Jul 2012 19:18:21 +0200, monarch_dodra <monarchdodra@gmail.com> wrote:
>>> 2) Is there a "correct" workaround?
>>
>> Exactly what you did. Though, for brevity, you would write this:
>>
>> void seed(T : UIntType)(T value = default_seed)
>
> Thanks
>
> I haven't seen this construct before. Can you tell me a bit more
> about it, or link me to some documentation about it?
>
> I suppose it means "T must be UIntType", but I'd enjoy having a broader understanding of it :)

Ali gave the general, I'll give the specifics.

is(T : Foo), void bar(T : Foo)(T t), and a few others (not really others,
they're exactly the same!) means 'T is implicitly convertible to Foo'.

What's the difference, you ask?

Consider:

    void foo(T)(T value) if (is(T == uint)) {}

Could you call this function like this:

    foo(3);

The answer is no. The compiler translates this to:

    foo!(typeof(3))(3);

And typeof(3) is not uint, it's int.

In contrast,

    void foo(T : uint)(T value) {}
    foo(3);

is also translated to

    foo!(typeof(3))(3);

and the compiler then checks if int is implicitly convertible to uint.
And so it is, so the compiler moves happily onwards.

There is a reason I included is(T : Foo) in the beginning, for you
can write the exact same constraint like this:

    void foo(T)(T value) if (is(T : uint)) {}

and it will compile just the same.


For more information on this construct, I would, in addition to the
links Ali provided, recommend you read this:

http://dlang.org/expression.html#IsExpression

IsExpressions are, however, probably the most hairy part of D, and
their understanding has proven troublesome to many (myself included,
though I believe I have grasped them now). Hence, most of their
functionality is wrapped in more easily understandable templates in
std.traits.

-- 
Simen
July 26, 2012
On Thursday, 26 July 2012 at 18:21:18 UTC, Ali Çehreli wrote:
> Search for "specialization" in the following resources:

Oh... "Specialization".

What with D's ability to conditionally implement, I had
completely forgotten about specialization. So that's how it's
done in D. Cool.

Thanks a lot.
July 26, 2012
On 2012-07-26 19:57, Simen Kjaeraas wrote:

>> 2) Is there a "correct" workaround?
>
> Exactly what you did. Though, for brevity, you would write this:
>
> void seed(T : UIntType)(T value = default_seed)

Since a template function is actually not wanted this would be the correct workaround:

void seed () (UIntType value = default_seed)

Less typing as well.

-- 
/Jacob Carlborg
July 26, 2012
On 7/26/12, Jacob Carlborg <doob@me.com> wrote:
> void seed () (UIntType value = default_seed)
>
> Less typing as well.

Yep. It's funny how this works at all. I mean a template with no template parameters is somehow still a template. :)
July 26, 2012
On Thursday, July 26, 2012 21:49:35 Andrej Mitrovic wrote:
> On 7/26/12, Jacob Carlborg <doob@me.com> wrote:
> > void seed () (UIntType value = default_seed)
> > 
> > Less typing as well.
> 
> Yep. It's funny how this works at all. I mean a template with no template parameters is somehow still a template. :)

It _is _ bit funny, but Ibelieve that  it comes from permitting empty template parameter lists. Without that, recursion with eponymous templates would become problematic. e.g.

enum template myTemplate(T...)
{
    static if(T.length == 0)
        enum myTemplate = 42;
    else
        enum myTemplate = T[0] * 3 + myTemplate!(T[1 .. $]);
}

needs to be able to take an empty parameter list. It's probably possible to make that work without allowing an outright empty parameter list that isn't even a variadic template, but I suspect that it's just easier to allow it.

- Jonathan M Davis