Re: recursive template expansion: Why does this not compile?

2018-03-22 Thread Ontonator via Digitalmars-d-learn
On Wednesday, 21 March 2018 at 23:05:22 UTC, Jonathan M Davis 
wrote:
On Wednesday, March 21, 2018 22:50:32 Ontonator via 
Digitalmars-d-learn wrote:

On Wednesday, 21 March 2018 at 06:39:22 UTC, ag0aep6g wrote:
> On 03/21/2018 01:47 AM, Ontonator wrote:
>> The following code does not compile:
>>> [...]
>>
>> It gives the error:
>>> [...]
>>
>> The aliases do not have to be aliases, as long as there is 
>> some reference to the class (e.g. method and variable 
>> declarations also work). What exactly is the reason for 
>> this error?

>
> Compiler bug. It works when you move the declaration of `B` 
> before the one of `A`. Order shouldn't matter there.


Is this a known bug, or should I report it?


If you can't find it searching on bugzilla, report it.

- Jonathan M Davis


https://issues.dlang.org/show_bug.cgi?id=18646


Re: recursive template expansion: Why does this not compile?

2018-03-21 Thread Jonathan M Davis via Digitalmars-d-learn
On Wednesday, March 21, 2018 22:50:32 Ontonator via Digitalmars-d-learn 
wrote:
> On Wednesday, 21 March 2018 at 06:39:22 UTC, ag0aep6g wrote:
> > On 03/21/2018 01:47 AM, Ontonator wrote:
> >> The following code does not compile:
> >>> [...]
> >>
> >> It gives the error:
> >>> [...]
> >>
> >> The aliases do not have to be aliases, as long as there is
> >> some reference to the class (e.g. method and variable
> >> declarations also work). What exactly is the reason for this
> >> error?
> >
> > Compiler bug. It works when you move the declaration of `B`
> > before the one of `A`. Order shouldn't matter there.
>
> Is this a known bug, or should I report it?

If you can't find it searching on bugzilla, report it.

- Jonathan M Davis



Re: recursive template expansion: Why does this not compile?

2018-03-21 Thread Ontonator via Digitalmars-d-learn

On Wednesday, 21 March 2018 at 06:39:22 UTC, ag0aep6g wrote:

On 03/21/2018 01:47 AM, Ontonator wrote:

The following code does not compile:

[...]


It gives the error:

[...]


The aliases do not have to be aliases, as long as there is 
some reference to the class (e.g. method and variable 
declarations also work). What exactly is the reason for this 
error?


Compiler bug. It works when you move the declaration of `B` 
before the one of `A`. Order shouldn't matter there.


Is this a known bug, or should I report it?


Re: recursive template expansion: Why does this not compile?

2018-03-21 Thread ag0aep6g via Digitalmars-d-learn

On 03/21/2018 01:47 AM, Ontonator wrote:

The following code does not compile:

void main() {}

class SuperClass {}

class TemplatedClass(T : SuperClass) {}

class A : SuperClass {
    alias T = TemplatedClass!B;
}

class B : SuperClass {
    alias T = TemplatedClass!C;
}

class C : SuperClass {}


It gives the error:
test.d(12): Error: class `test.TemplatedClass(T : SuperClass)` 
recursive template expansion

test.d(12):    while looking for match for TemplatedClass!(C)


The aliases do not have to be aliases, as long as there is some 
reference to the class (e.g. method and variable declarations also 
work). What exactly is the reason for this error?


Compiler bug. It works when you move the declaration of `B` before the 
one of `A`. Order shouldn't matter there.


Re: recursive template expansion: Why does this not compile?

2018-03-20 Thread Jonathan M Davis via Digitalmars-d-learn
On Wednesday, March 21, 2018 00:47:18 Ontonator via Digitalmars-d-learn 
wrote:
> The following code does not compile:
> > void main() {}
> >
> > class SuperClass {}
> >
> > class TemplatedClass(T : SuperClass) {}
> >
> > class A : SuperClass {
> >
> > alias T = TemplatedClass!B;
> >
> > }
> >
> > class B : SuperClass {
> >
> > alias T = TemplatedClass!C;
> >
> > }
> >
> > class C : SuperClass {}
>
> It gives the error:
> > test.d(12): Error: class `test.TemplatedClass(T : SuperClass)`
> > recursive template expansion
> > test.d(12):while looking for match for
> > TemplatedClass!(C)
>
> The aliases do not have to be aliases, as long as there is some
> reference to the class (e.g. method and variable declarations
> also work). What exactly is the reason for this error?

I'm not sure exactly what's happening, since I'm not very familiar with the
exactly how template specializations are defined, but the problem clearly
relates to the fact that you used a template specialization instead of a
template constraint. If you change TemplatedClass to

class TemplatedClass(T)
if(is(T : SuperClass))
{}

then the code compiles.

- Jonathan M Davis



recursive template expansion: Why does this not compile?

2018-03-20 Thread Ontonator via Digitalmars-d-learn

The following code does not compile:

void main() {}

class SuperClass {}

class TemplatedClass(T : SuperClass) {}

class A : SuperClass {
alias T = TemplatedClass!B;
}

class B : SuperClass {
alias T = TemplatedClass!C;
}

class C : SuperClass {}


It gives the error:
test.d(12): Error: class `test.TemplatedClass(T : SuperClass)` 
recursive template expansion
test.d(12):while looking for match for 
TemplatedClass!(C)


The aliases do not have to be aliases, as long as there is some 
reference to the class (e.g. method and variable declarations 
also work). What exactly is the reason for this error?


Re: Why does this not compile?

2018-03-07 Thread Steven Schveighoffer via Digitalmars-d

On 3/6/18 5:27 PM, Timon Gehr wrote:
The reasoning "the reference is stored in the type yet not part of the 
type" does not work for pure functions, as then you cannot offer an 
alternative explanation in terms of an external data store.


Yeah, the more I think about it, the more I think the context pointer 
simply needs to be part of the instance in the type system. I posted a 
threading issue elsewhere.


The problem is, correcting the bug will break a lot of code.

-Steve


Re: Why does this not compile?

2018-03-06 Thread Timon Gehr via Digitalmars-d

On 06.03.2018 17:19, Steven Schveighoffer wrote:


unittest {
 int n = 0;
 struct S {
 int fun() const { return n; }
 }
 immutable S s;
 assert(s.fun == 0);
 n++;
 assert(s.fun == 1); // Not so immutable now, are you?
}


That's not a demonstration of breaking immutability. counter-proof:

struct S
{
    static int x;
    int fun() const { return x; }
}

immutable S s;
assert(s.fun == 0);
S.x++;
assert(s.fun == 1);

In other words, if the struct can access the data considered "outside 
it's instance", then it it can return it, change it even.


Here's how to break immutability:

void main(){
int i = 0;
struct S{
const(int)* fun()const pure{
return 
}
}
immutable S s;
static const(int)* foo(immutable(S) s)pure{
return s.fun();
}
immutable(int) *pi=foo(s);
import std.stdio;
writeln(*pi); // 0
i+=1;
writeln(*pi); // 1
}

The reasoning "the reference is stored in the type yet not part of the 
type" does not work for pure functions, as then you cannot offer an 
alternative explanation in terms of an external data store.


https://issues.dlang.org/show_bug.cgi?id=18567


Re: Why does this not compile?

2018-03-06 Thread Steven Schveighoffer via Digitalmars-d

On 3/6/18 10:00 AM, Simen Kjærås wrote:

On Tuesday, 6 March 2018 at 13:56:30 UTC, Steven Schveighoffer wrote:

On 3/6/18 8:42 AM, Simen Kjærås wrote:

unittest {
 int i = 0;
 struct S {
 int n;
 void fun() const {
 i++;
 }
 }
 const S s;
 assert(i == 0);
 s.fun();
 assert(i == 1);
}


That, I would consider a bug. If it's not, then definitely, you should 
be able to implicitly cast to/from const.


So a bug report is in order. It should be decided one way or another 
-- either the context pointer is part of the struct type or it isn't.


immutable throws a wrench in the works for the idea that the context 
pointer is part of the struct. Consider the exact same example, but with 
immutable(S) instead of const(S). IMO, this indicates the context is not 
part of the struct (though the context *pointer* arguably is).


And just in case anyone doesn't immediately see how even disallowing the 
above would not solve the immutable problem:


unittest {
     int n = 0;
     struct S {
     int fun() const { return n; }
     }
     immutable S s;
     assert(s.fun == 0);
     n++;
     assert(s.fun == 1); // Not so immutable now, are you?
}


That's not a demonstration of breaking immutability. counter-proof:

struct S
{
   static int x;
   int fun() const { return x; }
}

immutable S s;
assert(s.fun == 0);
S.x++;
assert(s.fun == 1);

In other words, if the struct can access the data considered "outside 
it's instance", then it it can return it, change it even.


However, this is not a question that has been answered yet. The compiler 
clearly treats the context pointer as part of the instance in some 
cases, and not part of the instance in other cases.


Note that if the decision comes down that the context pointer is part of 
the instance, even *creating* an immutable S should be disallowed, as it 
clearly allows both mutable and immutable references.


Interestingly, replacing 'const' with 'immutable' on fun gives a 
compilation error: "immutable function 'foo.__unittest_foo_1_0.S.fun' 
cannot access mutable data 'n'".


Wat... This is like taking both sides at once (it's both part of the 
instance and not part of the instance).


This seems even weirder to me, but can certainly be taken as evidence in 
favor of your view. The same error message does *not* show up if n is 
instead a global variable.


This is very broken. And it needs attention.

-Steve


Re: Why does this not compile?

2018-03-06 Thread Steven Schveighoffer via Digitalmars-d

On 3/6/18 9:42 AM, Shachar Shemesh wrote:

I fail to see any reasoning[1] that disallows the former but allows the 
later.



1 - That is obviously not true. I see the reasoning all too well. Static 
vars are like globals, and you're not getting to them via the struct's 
instance. I would argue that, as far as the programmer, however, there 
is no difference. There is no semantic difference between allowing the 
first and not the second.


These aren't globals or static, they are no different than pointers 
(which is actually what they are).


Here is the problem with option 2: If you have a struct that is 
immutable (or shared), it can be passed without problems to another 
thread. If you can then start mucking with local variables in another 
thread with the assumption that they are thread-local, then you have 
broken the guarantee of immutable or shared. Even const can cause problems.


static data is different, in that it is either shared or thread-local, 
and then the path forward is quite clear. Passing thread-local data to 
another thread as if it were local to the recipient is like __gshared, 
and shouldn't be so easy to do.


-Steve


Re: Why does this not compile?

2018-03-06 Thread Shachar Shemesh via Digitalmars-d

On 06/03/18 17:00, Simen Kjærås wrote:
Interestingly, replacing 'const' with 'immutable' on fun gives a 
compilation error: "immutable function 'foo.__unittest_foo_1_0.S.fun' 
cannot access mutable data 'n'".


This just means it is completely and totally broken. Changing the 
"const" to "immutable" merely decreases the types that can be passed to 
the function. I see no case where it is legitimate for a const 
decoration to compile and an immutable one not.


Shachar


Re: Why does this not compile?

2018-03-06 Thread Simen Kjærås via Digitalmars-d
On Tuesday, 6 March 2018 at 13:56:30 UTC, Steven Schveighoffer 
wrote:

On 3/6/18 8:42 AM, Simen Kjærås wrote:

unittest {
     int i = 0;
     struct S {
     int n;
     void fun() const {
     i++;
     }
     }
     const S s;
     assert(i == 0);
     s.fun();
     assert(i == 1);
}


That, I would consider a bug. If it's not, then definitely, you 
should be able to implicitly cast to/from const.


So a bug report is in order. It should be decided one way or 
another -- either the context pointer is part of the struct 
type or it isn't.


immutable throws a wrench in the works for the idea that the 
context pointer is part of the struct. Consider the exact same 
example, but with immutable(S) instead of const(S). IMO, this 
indicates the context is not part of the struct (though the 
context *pointer* arguably is).


And just in case anyone doesn't immediately see how even 
disallowing the above would not solve the immutable problem:


unittest {
int n = 0;
struct S {
int fun() const { return n; }
}
immutable S s;
assert(s.fun == 0);
n++;
assert(s.fun == 1); // Not so immutable now, are you?
}

Interestingly, replacing 'const' with 'immutable' on fun gives a 
compilation error: "immutable function 
'foo.__unittest_foo_1_0.S.fun' cannot access mutable data 'n'".


This seems even weirder to me, but can certainly be taken as 
evidence in favor of your view. The same error message does *not* 
show up if n is instead a global variable.


--
  Simen


Re: Why does this not compile?

2018-03-06 Thread Shachar Shemesh via Digitalmars-d

Filed issue 18563

Shachar



Re: Why does this not compile?

2018-03-06 Thread Shachar Shemesh via Digitalmars-d

On 06/03/18 16:06, Steven Schveighoffer wrote:

On 3/6/18 8:56 AM, Steven Schveighoffer wrote:
So a bug report is in order. It should be decided one way or another 
-- either the context pointer is part of the struct type or it isn't.


There is a third possibility:

It's part of the type AND it's typed as const if it can be (i.e. none of 
the methods in the struct modify the context data, and any use of the 
context data implicitly casts from const).


-Steve


For what it's worth, I vote for option #2 (it isn't const even if the 
struct is), for the same reason that const structs can modify static 
variables - it's not part of the struct.


I'll phrase is another way, if this shouldn't compile:

unittest {
  int i;

  struct S {
int a;

void func() const {
  ++i;
}
  }
}

Then neither should this:
struct S {
  static int i;
  int a;

  void func() const {
++i;
  }
}

I fail to see any reasoning[1] that disallows the former but allows the 
later.


Shachar

1 - That is obviously not true. I see the reasoning all too well. Static 
vars are like globals, and you're not getting to them via the struct's 
instance. I would argue that, as far as the programmer, however, there 
is no difference. There is no semantic difference between allowing the 
first and not the second.


Re: Why does this not compile?

2018-03-06 Thread Steven Schveighoffer via Digitalmars-d

On 3/6/18 8:56 AM, Steven Schveighoffer wrote:

On 3/6/18 8:42 AM, Simen Kjærås wrote:

It's a bug. As pointed out elsewhere in this thread, it compiles 
correctly when there's no destructor. Essentially, this bug is caused 
by the context pointer being typed as void*, and becoming (of course) 
const(void*) for a const(S). If it'd been const(void)* in the first 
place, Shachar's code would have compiled and worked correctly.


Is it misleading for the context pointer to be const(void)*? In a way, 
maybe. However, it's opaquely typed, and its constness says nothing 
about what's on the other end. Also, the language completely 
disregards the constness in any case:


unittest {
 int i = 0;
 struct S {
 int n;
 void fun() const {
 i++;
 }
 }
 const S s;
 assert(i == 0);
 s.fun();
 assert(i == 1);
}


That, I would consider a bug. If it's not, then definitely, you should 
be able to implicitly cast to/from const.


So a bug report is in order. It should be decided one way or another -- 
either the context pointer is part of the struct type or it isn't.


There is a third possibility:

It's part of the type AND it's typed as const if it can be (i.e. none of 
the methods in the struct modify the context data, and any use of the 
context data implicitly casts from const).


-Steve


Re: Why does this not compile?

2018-03-06 Thread Steven Schveighoffer via Digitalmars-d

On 3/6/18 8:42 AM, Simen Kjærås wrote:

It's a bug. As pointed out elsewhere in this thread, it compiles 
correctly when there's no destructor. Essentially, this bug is caused by 
the context pointer being typed as void*, and becoming (of course) 
const(void*) for a const(S). If it'd been const(void)* in the first 
place, Shachar's code would have compiled and worked correctly.


Is it misleading for the context pointer to be const(void)*? In a way, 
maybe. However, it's opaquely typed, and its constness says nothing 
about what's on the other end. Also, the language completely disregards 
the constness in any case:


unittest {
     int i = 0;
     struct S {
     int n;
     void fun() const {
     i++;
     }
     }
     const S s;
     assert(i == 0);
     s.fun();
     assert(i == 1);
}


That, I would consider a bug. If it's not, then definitely, you should 
be able to implicitly cast to/from const.


So a bug report is in order. It should be decided one way or another -- 
either the context pointer is part of the struct type or it isn't.


-Steve


Re: Why does this not compile?

2018-03-06 Thread Simen Kjærås via Digitalmars-d
On Tuesday, 6 March 2018 at 12:00:43 UTC, Steven Schveighoffer 
wrote:

On 3/6/18 6:21 AM, Simen Kjærås wrote:
On Tuesday, 6 March 2018 at 10:03:54 UTC, Shachar Shemesh 
wrote:

void main() {
    struct S {
    uint value;

    ~this() {
    }
    }

    const S a = S(12);
    S b = a;
}

test.d(10): Error: cannot implicitly convert expression a of 
type const(S) to S


Looks like a bug to me - please file one in bugzilla.


Nope. It's not a bug. S contains a pointer, namely the context 
pointer for main.


It's a bug. As pointed out elsewhere in this thread, it compiles 
correctly when there's no destructor. Essentially, this bug is 
caused by the context pointer being typed as void*, and becoming 
(of course) const(void*) for a const(S). If it'd been 
const(void)* in the first place, Shachar's code would have 
compiled and worked correctly.


Is it misleading for the context pointer to be const(void)*? In a 
way, maybe. However, it's opaquely typed, and its constness says 
nothing about what's on the other end. Also, the language 
completely disregards the constness in any case:


unittest {
int i = 0;
struct S {
int n;
void fun() const {
i++;
}
}
const S s;
assert(i == 0);
s.fun();
assert(i == 1);
}

--
  Simen


Re: Why does this not compile?

2018-03-06 Thread Steven Schveighoffer via Digitalmars-d

On 3/6/18 7:44 AM, Shachar Shemesh wrote:

On 06/03/18 14:00, Steven Schveighoffer wrote:

On 3/6/18 6:21 AM, Simen Kjærås wrote:

On Tuesday, 6 March 2018 at 10:03:54 UTC, Shachar Shemesh wrote:

void main() {
    struct S {
    uint value;

    ~this() {
    }
    }

    const S a = S(12);
    S b = a;
}

test.d(10): Error: cannot implicitly convert expression a of type 
const(S) to S


Looks like a bug to me - please file one in bugzilla.


Nope. It's not a bug. S contains a pointer, namely the context pointer 
for main.


https://dlang.org/spec/struct.html#nested


Which does not explain why my code compiles if I remove the destructor.


If the struct is POD, there is no need to include the context pointer.

void main()
{
   struct POD { int x; }
   pragma(msg, POD.sizeof); // 4
   struct Nested { int x; void someMember() {} }
   pragma(msg, Nested.sizeof); // 16
}

-Steve


Re: Why does this not compile?

2018-03-06 Thread Shachar Shemesh via Digitalmars-d

On 06/03/18 14:00, Steven Schveighoffer wrote:

On 3/6/18 6:21 AM, Simen Kjærås wrote:

On Tuesday, 6 March 2018 at 10:03:54 UTC, Shachar Shemesh wrote:

void main() {
    struct S {
    uint value;

    ~this() {
    }
    }

    const S a = S(12);
    S b = a;
}

test.d(10): Error: cannot implicitly convert expression a of type 
const(S) to S


Looks like a bug to me - please file one in bugzilla.


Nope. It's not a bug. S contains a pointer, namely the context pointer 
for main.


https://dlang.org/spec/struct.html#nested


Which does not explain why my code compiles if I remove the destructor.

Shachar


Re: Why does this not compile?

2018-03-06 Thread Steven Schveighoffer via Digitalmars-d

On 3/6/18 6:21 AM, Simen Kjærås wrote:

On Tuesday, 6 March 2018 at 10:03:54 UTC, Shachar Shemesh wrote:

void main() {
    struct S {
    uint value;

    ~this() {
    }
    }

    const S a = S(12);
    S b = a;
}

test.d(10): Error: cannot implicitly convert expression a of type 
const(S) to S


Looks like a bug to me - please file one in bugzilla.


Nope. It's not a bug. S contains a pointer, namely the context pointer 
for main.


https://dlang.org/spec/struct.html#nested

Try this:

void main() {
   static struct S {
  uint value;
  ~this() {}
   }
   ... // rest of your code
}

-Steve


Re: Why does this not compile?

2018-03-06 Thread Shachar Shemesh via Digitalmars-d

On 06/03/18 12:16, Diego wrote:


You cannot assign a const element (`a`) to a non-const element (`b`) in 
`S b = a` expression.


Sure you can. During assignment you are making a copy. Why do you care 
whether the original is const?


Shachar


Re: Why does this not compile?

2018-03-06 Thread Simen Kjærås via Digitalmars-d

On Tuesday, 6 March 2018 at 10:03:54 UTC, Shachar Shemesh wrote:

void main() {
struct S {
uint value;

~this() {
}
}

const S a = S(12);
S b = a;
}

test.d(10): Error: cannot implicitly convert expression a of 
type const(S) to S


Looks like a bug to me - please file one in bugzilla.

--
  Simen


Re: Why does this not compile?

2018-03-06 Thread Diego via Digitalmars-d

On Tuesday, 6 March 2018 at 10:03:54 UTC, Shachar Shemesh wrote:

void main() {
struct S {
uint value;

~this() {
}
}

const S a = S(12);
S b = a;
}



You cannot assign a const element (`a`) to a non-const element 
(`b`) in `S b = a` expression. To make de assignment, you have to 
cast a to a non-constant expression:


S b = cast(S)a;

Or make `b` as const:

const S b = a;

Or, better, use auto keyword:

auto b = a;


Why does this not compile?

2018-03-06 Thread Shachar Shemesh via Digitalmars-d

void main() {
struct S {
uint value;

~this() {
}
}

const S a = S(12);
S b = a;
}

test.d(10): Error: cannot implicitly convert expression a of type 
const(S) to S


Doing *any* of the following makes the code compile:
* Making the struct "static"
* Making the struct global (essentially same as above)
* Removing the struct's destructor

I can kinda see why it won't compile without making it static. There is 
a hidden pointer to the frame that is const, implying the frame is also 
const. This constness would be overridden if the assignment is allowed 
to go through. I don't think this is a very good reason (see below), but 
I understand it.


What I do not understand is why removing the destructor solves the error.




While I get while the compiler treats the frame pointer as const, I 
should point out that if I add a static variable to the struct, that one 
remains mutable even when the instance itself is const. There is no 
inherent difference between a variable stored as static and a variable 
stored in the context frame.


And before you answer with "in D pointer constness is transitive", allow 
me to point something out: It is not possible to ever change the frame 
pointer of a struct. That pointer is, effectively, always const.


Shachar


Why does it not compile?

2011-03-24 Thread Morlan
import std.stdio;

void Foo(T:T*)(T arg) if(!is(T==int)) {
  writeln(arg of Foo:, arg, typeid(T));
}
void Foo(T:T*)(T arg) if(is(T==int)) {
  writeln(int Foo!);
}

void main() {
  Foo!(long*)(54);
}


Re: Why does it not compile?

2011-03-24 Thread bearophile
Morlan:

 ...

This compiles, 54 is an int:

import std.stdio;

void Foo(T: T*)(T arg) if(!is(T == int)) {
writeln(Arg of Foo: , arg,  , typeid(T));
}

void Foo(T: T*)(T arg) if(is(T == int)) {
writeln(int Foo!);
}

void main() {
  Foo!(long*)(54L);
}

Generally for questions like this, there is the D.learn newsgroup.

Bye,
bearophile


Re: Why does it not compile?

2011-03-24 Thread Morlan
I did not ask what to do to compile it. I knew that 54L would do. The problem is
that in the example I explicitely specify the template parameter as long* so 
there
is no reason for the compiler to try and guess T from the type of the function
argument. There is something wrong here.


Re: Why does it not compile?

2011-03-24 Thread Daniel Gibson

Am 24.03.2011 11:49, schrieb Morlan:

I did not ask what to do to compile it. I knew that 54L would do. The problem is
that in the example I explicitely specify the template parameter as long* so 
there
is no reason for the compiler to try and guess T from the type of the function
argument. There is something wrong here.


I agree.

void fun(long l) {}

void main() {
  long foo = 54;

  fun(42);
}

works, so that should work without an explicit cast as well.

Cheers,
- Daniel


Re: Why does it not compile?

2011-03-24 Thread Morlan
The program below compiles. Clearly the if constraints in my original example
are causing trouble. It seems like a bug to me.

import std.stdio;

void Foo(T:T*)(T arg) {
  writeln(arg of Foo:, arg, typeid(T));
}
void main() {
  Foo!(long*)(54);
}


Re: Why does it not compile?

2011-03-24 Thread bearophile
Morlan:

 I did not ask what to do to compile it. I knew that 54L would do. The problem 
 is
 that in the example I explicitely specify the template parameter as long* so 
 there
 is no reason for the compiler to try and guess T from the type of the function
 argument. There is something wrong here.

The compiler is not guessing the type here. It's just that the type the 
template is explicitly instantiated with, and the type T of the data, aren't 
the same. You see it better with this simpler example:


import std.stdio;

void foo(T)(T x) if(is(T == int)) {
writeln(1);
}

void foo(T)(T x) if(!is(T == int)) {
writeln(2);
}

void main() {
foo(1); // 1
foo(1L); // 2
foo!(int)(1); // 1
foo!(long)(1L); // 2
foo!(long)(1); // error
foo!(int)(1L); // error
}

Bye,
bearophile