www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - chain(const(array of class)) fails

reply SimonN <eiderdaus gmail.com> writes:
Hi,

we start with the following code snippet, which works.

     import std.algorithm;
     import std.range;
     import std.stdio;

     class A     { int val; }
     class B : A { this() { val = 3; } }
     class C : A { this() { val = 4; } }

     B[] b = [new B(), new B()];
     C[] c = [new C(), new C()];

     void main()
     {
         chain(b, c).each!(a => a.val.writeln);
     }

The output, as expected, is:

     3
     3
     4
     4

Now I change the declarations of B[] b and C[] c to the 
following, keeping
everything else in the code snippet the same:

     const(B[]) b = [new B(), new B()];
     const(C[]) c = [new C(), new C()];

This makes dmd 2.070 choke: ( http://dpaste.dzfl.pl/eee69fd03dd9 )

     Error: template std.range.chain cannot deduce function from 
argument
     types !()(const(B[]), const(C[])),
     candidates are: 
/opt/compilers/dmd2/include/std/range/package.d(804):
     std.range.chain(Ranges...)(Ranges rs) if (Ranges.length > 0 &&
     allSatisfy!(iseputRange, staticMap!(Unqual, Ranges)) && 
!is(CommonType!(
     staticMap!(ElementType, staticMap!(Unqual, Ranges))) == void))

What's stumping me -- constness doesn't make dmd choke on ranges 
of
numbers. If I replace the classes B and C with simple 'int' and 
'double',
this compiles again:

     const(int[])    b = [1, 2];
     const(double[]) c = [3.3, 4.4];
     void main() { chain(b, c).each!(a => a.writeln); }

Why does it fail for const(array of class)?
Is any template magic about Unqual or staticMap relevant here?

-- Simon
Jan 31
next sibling parent reply Nicholas Wilson <iamthewilsonator hotmail.com> writes:
On Sunday, 31 January 2016 at 21:22:06 UTC, SimonN wrote:
 Hi,

 we start with the following code snippet, which works.

     import std.algorithm;
     import std.range;
     import std.stdio;

     class A     { int val; }
     class B : A { this() { val = 3; } }
     class C : A { this() { val = 4; } }

     B[] b = [new B(), new B()];
     C[] c = [new C(), new C()];

     void main()
     {
         chain(b, c).each!(a => a.val.writeln);
     }

 The output, as expected, is:

     3
     3
     4
     4

 Now I change the declarations of B[] b and C[] c to the 
 following, keeping
 everything else in the code snippet the same:

     const(B[]) b = [new B(), new B()];
     const(C[]) c = [new C(), new C()];

 This makes dmd 2.070 choke: ( 
 http://dpaste.dzfl.pl/eee69fd03dd9 )

     Error: template std.range.chain cannot deduce function from 
 argument
     types !()(const(B[]), const(C[])),
     candidates are: 
 /opt/compilers/dmd2/include/std/range/package.d(804):
     std.range.chain(Ranges...)(Ranges rs) if (Ranges.length > 0 
 &&
     allSatisfy!(iseputRange, staticMap!(Unqual, Ranges)) && 
 !is(CommonType!(
     staticMap!(ElementType, staticMap!(Unqual, Ranges))) == 
 void))

 What's stumping me -- constness doesn't make dmd choke on 
 ranges of
 numbers. If I replace the classes B and C with simple 'int' and 
 'double',
 this compiles again:

     const(int[])    b = [1, 2];
     const(double[]) c = [3.3, 4.4];
     void main() { chain(b, c).each!(a => a.writeln); }

 Why does it fail for const(array of class)?
 Is any template magic about Unqual or staticMap relevant here?

 -- Simon
types !()(const(B[]), const(C[])),
     candidates are: 
 /opt/compilers/dmd2/include/std/range/package.d(804):
     std.range.chain(Ranges...)(Ranges rs) if (Ranges.length > 0 
 &&
     allSatisfy!(iseputRange, staticMap!(Unqual, Ranges)) && 
 !is(CommonType!(
     staticMap!(ElementType, staticMap!(Unqual, Ranges))) == 
 void))
Unqaul means remove any const or immutable torn the type StaticMap is like a compile time map What this error message says is that there is one candidate function that matches what you are attempting to do. and that chain takes a variadic argument and each of those arguments must 1) when unqualified be an input range (Basically you can foreach over it) 2) that the common type of the element type of the unqualified variadic argument types is not void (in this case not arrays of void) Have you tried changing The declaration of a and b to const(A[])? Also have you tried with other reference type (e.g. assoc arrays pointers)? Nic
Jan 31
parent SimonN <eiderdaus gmail.com> writes:
Sorry for late reply -- but I got around to test a couple more 
cases!

On Monday, 1 February 2016 at 00:19:44 UTC, Nicholas Wilson wrote:
 Unqaul means remove any const or immutable torn the type
Okay, that sounds like our 'const' shouldn't matter. 'const' is the outermost qualifier, and stripping that leaves us with B[] and C[], which were chainable earlier.
 StaticMap is like a compile time map
 What this error message says is that there is one candidate 
 function that matches what you are attempting to do. and that 
 chain takes a variadic argument and each of those arguments must
 1) when unqualified be an input range (Basically you can 
 foreach over it)
Yep, const(B[]) and const(C[]) can be foreached. My workaround has been to replace chain() with several foreaches.
 2) that the common type of the element type of the unqualified 
 variadic argument types is not void (in this case not arrays of 
 void)
 Have you tried changing The declaration of a and b to 
 const(A[])?
Surprisingly, this compiles and gives the desired output: const(B[]) b = [ new B(), new B() ]; const(A[]) c = [ new C(), new C() ]; // A instead of C chain(b, c).each!(a => a.val.writeln); With two arguments, const(array) has worked iff at least one range is of the base type. Only if none were of the base type, I got the error. Apparently, the template is smart enough to infer the common base type without 'const', but needs to be fed the basetype in case of 'const'. My gut feeling is that I should report this as a bug against phobos...
 Also have you tried with other reference type (e.g. assoc 
 arrays pointers)?
immutable(B[int]) b; immutable(C[int]) c; chain(b.byValue, c.byValue).each!(a => a.val.writeln); Error is the same as for the classes: template std.range.chain cannot deduce function from argument types !()(Result, Result), candidates are: /* snip */ To get this error, again, if at least one range is 'immutable(A[int]).byValue', i.e., using the base class A, the template instantiates with no problems. -- Simon
Feb 01
prev sibling parent reply Marc =?UTF-8?B?U2Now7x0eg==?= <schuetzm gmx.net> writes:
The constraint that fails is the one with `CommonType`:

     pragma(msg, CommonType!(const(B), const(C))); // void

`CommonType` uses the `?:` operator to derive the common type:

     writeln(true ? b : c);
     // Error: incompatible types for ((b) : (c)): 'const(B[])' 
and 'const(C[])'
     writeln(true ? b[0] : c[0]);
     // Error: incompatible types for ((b[0]) : (c[0])): 
'const(B)' and 'const(C)'

At the moment I can't see a reason why that shouldn't work.
Feb 02
parent reply Marc =?UTF-8?B?U2Now7x0eg==?= <schuetzm gmx.net> writes:
On Tuesday, 2 February 2016 at 09:51:52 UTC, Marc Schütz wrote:
 The constraint that fails is the one with `CommonType`:

     pragma(msg, CommonType!(const(B), const(C))); // void

 `CommonType` uses the `?:` operator to derive the common type:

     writeln(true ? b : c);
     // Error: incompatible types for ((b) : (c)): 'const(B[])' 
 and 'const(C[])'
     writeln(true ? b[0] : c[0]);
     // Error: incompatible types for ((b[0]) : (c[0])): 
 'const(B)' and 'const(C)'

 At the moment I can't see a reason why that shouldn't work.
This change broke it: https://github.com/D-Programming-Language/dmd/pull/125 I filed a bug report: https://issues.dlang.org/show_bug.cgi?id=15638
Feb 02
parent SimonN <eiderdaus gmail.com> writes:
On Tuesday, 2 February 2016 at 10:58:35 UTC, Marc Schütz wrote:
 The constraint that fails is the one with `CommonType`:
 `CommonType` uses the `?:` operator to derive the common type:
I filed a bug report: https://issues.dlang.org/show_bug.cgi?id=15638
Interesting reduced case, so it wasn't chain after all. Thanks for filing the issue already; also thanks to Nic for good test cases. I think Adam D. Ruppe wanted to push more informative template errors -- they'd come in handy. :-) -- Simon
Feb 02