www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Return type of std.algorithm.map

reply James Fisher <jameshfisher gmail.com> writes:
--20cf3054a013e8e7e704a77b2421
Content-Type: text/plain; charset=UTF-8

To date, I've been using D in much the same way I used C++, without heavy
use of templates.  Now I'm trying out a more functional style using
std.algorithm.  However I'm pretty much stuck at the first hurdle: map.
 With type inference, this works:

import std.algorithm;
import std.stdio;

void main() {
  auto start = [1,2,3,4,5];
  auto squares = map!((a) { return a * a; })(start);
  writeln(squares);
}


Without type inference (obviously necessary beyond trivial examples), it'd
be nice to do:

import std.algorithm;
import std.stdio;

void main() {
  int[] start = [1,2,3,4,5];
  int[] squares = map!((a) { return a * a; })(start);
  writeln(squares);
}


but this gives "Error: cannot implicitly convert expression (map(start)) of
type Result to int[]".  That opaque type "Result" is weird (not
parameterized on "int"?), but OK, let's try that:

import std.algorithm;
import std.stdio;

void main() {
  int[] start = [1,2,3,4,5];
  Result squares = map!((a) { return a * a; })(start);
  writeln(squares);
}


gives "undefined identifier Result".  Not sure why, but OK.  I can't see
examples in the docs of explicit type declarations -- annoyingly they all
use "auto".

However, they do tell me that map "returns a range".  Assuming all
definitions of ranges are in std.range, there's no such thing as a "Range"
interface, so it's not that.  The most general interfaces I can see are
InputRange(E) and OutputRange(E).  It certainly can't be an OutputRange, so
I guess it must satisfy InputRange, presumably type-parameterized with
"int".  So this should work:

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

void main() {
  int[] start = [1,2,3,4,5];
  InputRange!int squares = map!((a) { return a * a; })(start);
  writeln(squares);
}


But the compiler complains "cannot implicitly convert expression
(map(start)) of type Result to std.range.InputRange!(int).InputRange".
 That's weird, because "std.range.InputRange!(int).InputRange" doesn't even
look like a type.

I've tried all manner of combinations here, but nothing works.  Seems like
there's something fundamental I'm not understanding.

--20cf3054a013e8e7e704a77b2421
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable

To date, I&#39;ve been using D in much the same way I used C++, without hea=
vy use of templates. =C2=A0Now I&#39;m trying out a more functional style u=
sing std.algorithm. =C2=A0However I&#39;m pretty much stuck at the first hu=
rdle: map. =C2=A0With type inference, this works:<div>
<br></div><blockquote class=3D"webkit-indent-blockquote" style=3D"margin: 0=
 0 0 40px; border: none; padding: 0px;"><div>import std.algorithm;</div><di=
v>import std.stdio;</div><div><br></div><div>void main() {</div><div>=C2=A0=
 auto start =3D [1,2,3,4,5];</div>
<div>=C2=A0 auto squares =3D map!((a) { return a * a; })(start);</div><div>=
=C2=A0 writeln(squares);</div><div>}</div></blockquote><div><br></div><div>=
Without type inference (obviously necessary beyond trivial examples), it&#3=
9;d be nice to do:</div>
<div><br></div><blockquote class=3D"webkit-indent-blockquote" style=3D"marg=
in: 0 0 0 40px; border: none; padding: 0px;"><div><div>import std.algorithm=
;</div></div><div><div>import std.stdio;</div></div><div><div><br></div></d=
iv>
<div><div>void main() {</div></div><div><div>=C2=A0 int[] start =3D [1,2,3,=
4,5];</div></div><div><div>=C2=A0 int[] squares =3D map!((a) { return a * a=
; })(start);</div></div><div><div>=C2=A0 writeln(squares);</div></div><div>=
<div>}</div></div>
</blockquote><div><br></div><div>but this gives &quot;Error: cannot implici=
tly convert expression (map(start)) of type Result to int[]&quot;. =C2=A0Th=
at opaque type &quot;Result&quot; is weird (not parameterized on &quot;int&=
quot;?), but OK, let&#39;s try that:</div>
<div><br></div><blockquote class=3D"webkit-indent-blockquote" style=3D"marg=
in: 0 0 0 40px; border: none; padding: 0px;"><div><div>import std.algorithm=
;</div></div><div><div>import std.stdio;</div></div><div><div><br></div></d=
iv>
<div><div>void main() {</div></div><div><div>=C2=A0 int[] start =3D [1,2,3,=
4,5];</div></div><div><div>=C2=A0 Result squares =3D map!((a) { return a * =
a; })(start);</div></div><div><div>=C2=A0 writeln(squares);</div></div><div=
<div>}</div></div>

ot;. =C2=A0Not sure why, but OK. =C2=A0I can&#39;t see examples in the docs= of explicit type declarations -- annoyingly they all use &quot;auto&quot;.= </div> <div><br></div><div>However, they do tell me that map &quot;returns a range= &quot;. =C2=A0Assuming all definitions of ranges are in std.range, there&#3= 9;s no such thing as a &quot;Range&quot; interface, so it&#39;s not that. = =C2=A0The most general interfaces I can see are InputRange(E) and OutputRan= ge(E). =C2=A0It certainly can&#39;t be an OutputRange, so I guess it must s= atisfy InputRange, presumably type-parameterized with &quot;int&quot;. =C2= =A0So this should work:</div> <div><br></div><blockquote class=3D"webkit-indent-blockquote" style=3D"marg= in: 0 0 0 40px; border: none; padding: 0px;"><div><div>import std.algorithm= ;</div></div><div><div>import std.stdio;</div></div><div><div>import std.ra= nge;</div> </div><div><div><br></div></div><div><div>void main() {</div></div><div><di= v>=C2=A0 int[] start =3D [1,2,3,4,5];</div></div><div><div>=C2=A0 InputRang= e!int squares =3D map!((a) { return a * a; })(start);</div></div><div><div>= =C2=A0 writeln(squares);</div> </div><div><div>}</div></div></blockquote><div><br></div><div>But the compi= ler complains &quot;cannot implicitly convert expression (map(start)) of ty= pe Result to std.range.InputRange!(int).InputRange&quot;. =C2=A0That&#39;s = weird, because &quot;std.range.InputRange!(int).InputRange&quot; doesn&#39;= t even look like a type.</div> <div><br></div><div>I&#39;ve tried all manner of combinations here, but not= hing works. =C2=A0Seems like there&#39;s something fundamental I&#39;m not = understanding.</div> --20cf3054a013e8e7e704a77b2421--
Jul 07 2011
next sibling parent bearophile <bearophileHUGS lycos.com> writes:
James Fisher:

 To date, I've been using D in much the same way I used C++, without heavy
 use of templates.  Now I'm trying out a more functional style using
 std.algorithm.  However I'm pretty much stuck at the first hurdle: map.

Welcome to functional D :-)
 The most general interfaces I can see are InputRange(E) and OutputRange(E).

In D language there is about as much support for OOP as in Java (and more), but in practice OO interfaces are not used significantly in the D standard library. So those are a different kind of "interfaces", they are a bit more like C++0x Concepts, they are very statically typed. So while they are organized in a hierarchy, you can't assign them as OO interfaces. You generally use type inference to assign the type of map. In functional programming a bit of type inference is not optional, it's almost needed. map() in D is lazy, it doesn't return an array, but a lazily iterable range. If you want an eager dynamic array you may use array(): array(map!((a) { return a * a; })(start)); If you don't want to use type inference for the return result of map, you have to take a look at the source code of std.functional, read what type is exactly map, and copy it. Generally this is not done in normal user code. Bye, bearophile
Jul 07 2011
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Thu, 07 Jul 2011 10:00:48 -0400, James Fisher <jameshfisher gmail.com>  
wrote:

 To date, I've been using D in much the same way I used C++, without heavy
 use of templates.  Now I'm trying out a more functional style using
 std.algorithm.  However I'm pretty much stuck at the first hurdle: map.
  With type inference, this works:

 import std.algorithm;
 import std.stdio;

 void main() {
   auto start = [1,2,3,4,5];
   auto squares = map!((a) { return a * a; })(start);
   writeln(squares);
 }


 Without type inference (obviously necessary beyond trivial examples),

Type inference is useful everywhere, at any level of complexity. Where it's not useful is declarations, for example, declaring the type of a struct or class member. However, typeof should work to use type inference there.
 it'd
 be nice to do:

 import std.algorithm;
 import std.stdio;

 void main() {
   int[] start = [1,2,3,4,5];
   int[] squares = map!((a) { return a * a; })(start);
   writeln(squares);
 }


 but this gives "Error: cannot implicitly convert expression (map(start))  
 of
 type Result to int[]".  That opaque type "Result" is weird (not
 parameterized on "int"?), but OK, let's try that:

 import std.algorithm;
 import std.stdio;

 void main() {
   int[] start = [1,2,3,4,5];
   Result squares = map!((a) { return a * a; })(start);
   writeln(squares);
 }


 gives "undefined identifier Result".  Not sure why, but OK.  I can't see
 examples in the docs of explicit type declarations -- annoyingly they all
 use "auto".

OK, so this is kind of a weird case. std.algorithm.map returns an inner struct, which means, it has no public name. But then how can you even use it? Well, it just doesn't have a public *name*, but it still can be used outside the function. It's definitely an oddball. However, what's nice about it is that you can encapsulate the struct inside the one place it is used. You can see the definition of map here: https://github.com/D-Programming-Language/phobos/blob/master/std/algorithm.d#L366 And a few lines down, the declaration of Result. You can use typeof if you want to get the type, but again, auto is much better unless you are declaring something.
 However, they do tell me that map "returns a range".  Assuming all
 definitions of ranges are in std.range, there's no such thing as a  
 "Range"
 interface, so it's not that.  The most general interfaces I can see are
 InputRange(E) and OutputRange(E).  It certainly can't be an OutputRange,  
 so
 I guess it must satisfy InputRange, presumably type-parameterized with
 "int".

No, a range is a concept, meaning it is a compile-time interface. Any type which satisfies the requirements of the input range can be a range, even non-polymorphic types. Even an array is a range.
  So this should work:

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

 void main() {
   int[] start = [1,2,3,4,5];
   InputRange!int squares = map!((a) { return a * a; })(start);
   writeln(squares);
 }


 But the compiler complains "cannot implicitly convert expression
 (map(start)) of type Result to std.range.InputRange!(int).InputRange".

Right, because it's not a derivative of that interface, it's its own type, defined only inside the function. Yeah, I know it's confusing :)
  That's weird, because "std.range.InputRange!(int).InputRange" doesn't  
 even
 look like a type.

std.range is the module, but I assume you already know that. But one of the coolest things about D templates is the eponymous rule. That is, if you declare a template, and that template has exactly one member, and that one member is named the same as the template, then x!(y) becomes the equivalent of x!(y).x. For example: template t(T) { class t { T val; } } t!(int) is equivalent to t!(int).t In other words, a template is a *namespace* for declarations using the template parameters. And in this special case, you can omit the member of the namespace you are accessing. Then what follows is that: class t(T) { T val; } is shorthand for the above. But the compiler maintains the namespace.member nomenclature, which is why you see that in the error message. -Steve
Jul 07 2011
prev sibling next sibling parent James Fisher <jameshfisher gmail.com> writes:
--bcaec52e6045b3076304a7902d67
Content-Type: text/plain; charset=UTF-8

OK, good replies.  Cool.  So the two places I thought I'd need to use
explicit types are in parameter and return types.  Say, a function returns
the result of map, and another consumes it to print it.  The consuming
function seems to work with templating:

void printSquares(T)(T squares) {
  writeln(squares);
}

void main() {
  int[] start = [1,2,3,4,5];
  auto squares = map!((a) { return a * a; })(start);
  printSquares(squares);
}


However, returning the result of map doesn't seem to work so well with the
same method:

T getSquares(T)() {
  int[] start = [1,2,3,4,5];
  return map!((a) { return a * a; })(start);
}

void main() {
  auto squares = getSquares();
  writeln(squares);
}


Gives the errors:

test.d(11): Error: template test.getSquares(T) does not match any function
template declaration
test.d(11): Error: template test.getSquares(T) cannot deduce template
function from argument types !()()


But this does work with auto return type inference:

auto getSquares() {
  int[] start = [1,2,3,4,5];
  return map!((a) { return a * a; })(start);
}

void main() {
  auto squares = getSquares();
  writeln(squares);
}


So ... stuff works, but I'm not really sure why one uses function templating
and the other uses return type inference.  Any answers?

On Thu, Jul 7, 2011 at 7:31 PM, Steven Schveighoffer <schveiguy yahoo.com>wrote:

 On Thu, 07 Jul 2011 10:00:48 -0400, James Fisher <jameshfisher gmail.com>
 wrote:

  To date, I've been using D in much the same way I used C++, without heavy
 use of templates.  Now I'm trying out a more functional style using
 std.algorithm.  However I'm pretty much stuck at the first hurdle: map.
  With type inference, this works:

 import std.algorithm;
 import std.stdio;

 void main() {
  auto start = [1,2,3,4,5];
  auto squares = map!((a) { return a * a; })(start);
  writeln(squares);
 }


 Without type inference (obviously necessary beyond trivial examples),

Type inference is useful everywhere, at any level of complexity. Where it's not useful is declarations, for example, declaring the type of a struct or class member. However, typeof should work to use type inference there. it'd
 be nice to do:

 import std.algorithm;
 import std.stdio;

 void main() {
  int[] start = [1,2,3,4,5];
  int[] squares = map!((a) { return a * a; })(start);
  writeln(squares);
 }


 but this gives "Error: cannot implicitly convert expression (map(start))
 of
 type Result to int[]".  That opaque type "Result" is weird (not
 parameterized on "int"?), but OK, let's try that:

 import std.algorithm;
 import std.stdio;

 void main() {
  int[] start = [1,2,3,4,5];
  Result squares = map!((a) { return a * a; })(start);
  writeln(squares);
 }


 gives "undefined identifier Result".  Not sure why, but OK.  I can't see
 examples in the docs of explicit type declarations -- annoyingly they all
 use "auto".

OK, so this is kind of a weird case. std.algorithm.map returns an inner struct, which means, it has no public name. But then how can you even use it? Well, it just doesn't have a public *name*, but it still can be used outside the function. It's definitely an oddball. However, what's nice about it is that you can encapsulate the struct inside the one place it is used. You can see the definition of map here: https://github.com/D-** Programming-Language/phobos/**blob/master/std/algorithm.d#**L366<https://github.com/D-Programming-Language/phobos/blob/master/std/algorithm.d#L366> And a few lines down, the declaration of Result. You can use typeof if you want to get the type, but again, auto is much better unless you are declaring something. However, they do tell me that map "returns a range". Assuming all
 definitions of ranges are in std.range, there's no such thing as a "Range"
 interface, so it's not that.  The most general interfaces I can see are
 InputRange(E) and OutputRange(E).  It certainly can't be an OutputRange,
 so
 I guess it must satisfy InputRange, presumably type-parameterized with
 "int".

No, a range is a concept, meaning it is a compile-time interface. Any type which satisfies the requirements of the input range can be a range, even non-polymorphic types. Even an array is a range. So this should work:
 import std.algorithm;
 import std.stdio;
 import std.range;

 void main() {
  int[] start = [1,2,3,4,5];
  InputRange!int squares = map!((a) { return a * a; })(start);
  writeln(squares);
 }


 But the compiler complains "cannot implicitly convert expression
 (map(start)) of type Result to std.range.InputRange!(int).**InputRange".

Right, because it's not a derivative of that interface, it's its own type, defined only inside the function. Yeah, I know it's confusing :) That's weird, because "std.range.InputRange!(int).**InputRange" doesn't
 even
 look like a type.

std.range is the module, but I assume you already know that. But one of the coolest things about D templates is the eponymous rule. That is, if you declare a template, and that template has exactly one member, and that one member is named the same as the template, then x!(y) becomes the equivalent of x!(y).x. For example: template t(T) { class t { T val; } } t!(int) is equivalent to t!(int).t In other words, a template is a *namespace* for declarations using the template parameters. And in this special case, you can omit the member of the namespace you are accessing. Then what follows is that: class t(T) { T val; } is shorthand for the above. But the compiler maintains the namespace.member nomenclature, which is why you see that in the error message. -Steve

--bcaec52e6045b3076304a7902d67 Content-Type: text/html; charset=UTF-8 Content-Transfer-Encoding: quoted-printable OK, good replies. =C2=A0Cool. =C2=A0So the two places I thought I&#39;d nee= d to use explicit types are in parameter and return types. =C2=A0Say, a fun= ction returns the result of map, and another consumes it to print it. =C2= =A0The consuming function seems to work with templating:<div> <br></div><blockquote style=3D"margin:0 0 0 40px;border:none;padding:0px"><= div><div>void printSquares(T)(T squares) {</div></div><div><div>=C2=A0 writ= eln(squares);</div></div><div><div>}</div> </div><div><div><br></div></div><div><div>void main() {</div></div><div><di= v>=C2=A0 int[] start =3D [1,2,3,4,5];</div></div><div><div>=C2=A0 auto squa= res =3D map!((a) { return a * a; })(start);</div></div><div><div>=C2=A0 pri= ntSquares(squares);</div> </div><div><div>}</div></div></blockquote><div><br></div><div>However, retu= rning the result of map doesn&#39;t seem to work so well with the same meth= od:</div><div><br></div><blockquote class=3D"webkit-indent-blockquote" styl= e=3D"margin: 0 0 0 40px; border: none; padding: 0px;"> <div><div><div><div><div>T getSquares(T)() {</div></div></div></div></div><= div><div><div><div><div>=C2=A0 int[] start =3D [1,2,3,4,5];</div></div></di= v></div></div><div><div><div><div><div>=C2=A0 return map!((a) { return a * = a; })(start);</div> </div></div></div></div><div><div><div><div><div>}</div></div></div></div><= /div><div><div><div><div><div><br></div></div></div></div></div><div><div><= div><div><div>void main() {</div></div></div></div></div><div><div><div> <div><div>=C2=A0 auto squares =3D getSquares();</div></div></div></div></di= v><div><div><div><div><div>=C2=A0 writeln(squares);</div></div></div></div>= </div><div><div><div><div><div>}</div></div></div></div></div></blockquote>= <div><div> <div><div><div><br></div><div>Gives the errors:</div><div><br></div></div><= /div></div></div><blockquote class=3D"webkit-indent-blockquote" style=3D"ma= rgin: 0 0 0 40px; border: none; padding: 0px;"><div><div><div><div><div><di= v> test.d(11): Error: template test.getSquares(T) does not match any function = template declaration</div></div></div></div></div></div><div><div><div><div=
<div><div>test.d(11): Error: template test.getSquares(T) cannot deduce tem=

</div></div></div></div></div></blockquote><div><div><div><div><div><br></d= iv><div>But this does work with auto return type inference:</div><div><br><= /div></div></div></div></div><blockquote class=3D"webkit-indent-blockquote"= style=3D"margin: 0 0 0 40px; border: none; padding: 0px;"> <div><div><div><div><div><div>auto getSquares() {</div></div></div></div></= div></div><div><div><div><div><div><div>=C2=A0 int[] start =3D [1,2,3,4,5];= </div></div></div></div></div></div><div><div><div><div><div><div>=C2=A0 re= turn map!((a) { return a * a; })(start);</div> </div></div></div></div></div><div><div><div><div><div><div>}</div></div></= div></div></div></div><div><div><div><div><div><div><br></div></div></div><= /div></div></div><div><div><div><div><div><div>void main() {</div></div> </div></div></div></div><div><div><div><div><div><div>=C2=A0 auto squares = =3D getSquares();</div></div></div></div></div></div><div><div><div><div><d= iv><div>=C2=A0 writeln(squares);</div></div></div></div></div></div><div><d= iv><div><div> <div><div>}</div></div></div></div></div></div></blockquote><div><br></div>= So ... stuff works, but I&#39;m not really sure why one uses function templ= ating and the other uses return type inference. =C2=A0Any answers?<br><div>= <div> <div><div><br><div class=3D"gmail_quote">On Thu, Jul 7, 2011 at 7:31 PM, St= even Schveighoffer <span dir=3D"ltr">&lt;<a href=3D"mailto:schveiguy yahoo.= com" target=3D"_blank">schveiguy yahoo.com</a>&gt;</span> wrote:<br> <blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1p= x #ccc solid;padding-left:1ex"><div>On Thu, 07 Jul 2011 10:00:48 -0400, Jam= es Fisher &lt;<a href=3D"mailto:jameshfisher gmail.com" target=3D"_blank">j= ameshfisher gmail.com</a>&gt; wrote:<br> <br> </div><blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-l= eft:1px #ccc solid;padding-left:1ex"><div> To date, I&#39;ve been using D in much the same way I used C++, without hea= vy<br> use of templates. =C2=A0Now I&#39;m trying out a more functional style usin= g<br> std.algorithm. =C2=A0However I&#39;m pretty much stuck at the first hurdle:= map.<br></div><div> =C2=A0With type inference, this works:<br> <br> import std.algorithm;<br> import std.stdio;<br> <br> void main() {<br> =C2=A0auto start =3D [1,2,3,4,5];<br> =C2=A0auto squares =3D map!((a) { return a * a; })(start);<br> =C2=A0writeln(squares);<br> }<br> <br> <br> Without type inference (obviously necessary beyond trivial examples),<br> </div></blockquote> <br> Type inference is useful everywhere, at any level of complexity.<br> <br> Where it&#39;s not useful is declarations, for example, declaring the type = of a struct or class member. =C2=A0However, typeof should work to use type = inference there.<div><br> <br> <blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1p= x #ccc solid;padding-left:1ex"> it&#39;d<br> be nice to do:<br> <br> import std.algorithm;<br> import std.stdio;<br> <br> void main() {<br> =C2=A0int[] start =3D [1,2,3,4,5];<br> =C2=A0int[] squares =3D map!((a) { return a * a; })(start);<br> =C2=A0writeln(squares);<br> }<br> <br> <br> but this gives &quot;Error: cannot implicitly convert expression (map(start= )) of<br> type Result to int[]&quot;. =C2=A0That opaque type &quot;Result&quot; is we= ird (not<br> parameterized on &quot;int&quot;?), but OK, let&#39;s try that:<br> <br> import std.algorithm;<br> import std.stdio;<br> <br> void main() {<br> =C2=A0int[] start =3D [1,2,3,4,5];<br> =C2=A0Result squares =3D map!((a) { return a * a; })(start);<br> =C2=A0writeln(squares);<br> }<br> <br> <br> gives &quot;undefined identifier Result&quot;. =C2=A0Not sure why, but OK. = =C2=A0I can&#39;t see<br> examples in the docs of explicit type declarations -- annoyingly they all<b= r> use &quot;auto&quot;.<br> </blockquote> <br></div> OK, so this is kind of a weird case. =C2=A0std.algorithm.map returns an inn= er struct, which means, it has no public name. =C2=A0But then how can you e= ven use it? =C2=A0Well, it just doesn&#39;t have a public *name*, but it st= ill can be used outside the function. =C2=A0It&#39;s definitely an oddball.= =C2=A0However, what&#39;s nice about it is that you can encapsulate the st= ruct inside the one place it is used.<br> <br> You can see the definition of map here: <a href=3D"https://github.com/D-Pro= gramming-Language/phobos/blob/master/std/algorithm.d#L366" target=3D"_blank= ">https://github.com/D-<u></u>Programming-Language/phobos/<u></u>blob/maste= r/std/algorithm.d#<u></u>L366</a><br> <br> And a few lines down, the declaration of Result.<br> <br> You can use typeof if you want to get the type, but again, auto is much bet= ter unless you are declaring something.<div><br> <br> <blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1p= x #ccc solid;padding-left:1ex"> However, they do tell me that map &quot;returns a range&quot;. =C2=A0Assumi= ng all<br> definitions of ranges are in std.range, there&#39;s no such thing as a &quo= t;Range&quot;<br> interface, so it&#39;s not that. =C2=A0The most general interfaces I can se= e are<br> InputRange(E) and OutputRange(E). =C2=A0It certainly can&#39;t be an Output= Range, so<br> I guess it must satisfy InputRange, presumably type-parameterized with<br> &quot;int&quot;.<br> </blockquote> <br></div> No, a range is a concept, meaning it is a compile-time interface. =C2=A0Any= type which satisfies the requirements of the input range can be a range, e= ven non-polymorphic types. =C2=A0Even an array is a range.<div><br> <br> <blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1p= x #ccc solid;padding-left:1ex"> =C2=A0So this should work:<br> <br> import std.algorithm;<br> import std.stdio;<br> import std.range;<br> <br> void main() {<br> =C2=A0int[] start =3D [1,2,3,4,5];<br> =C2=A0InputRange!int squares =3D map!((a) { return a * a; })(start);<br> =C2=A0writeln(squares);<br> }<br> <br> <br> But the compiler complains &quot;cannot implicitly convert expression<br> (map(start)) of type Result to std.range.InputRange!(int).<u></u>InputRange= &quot;.<br> </blockquote> <br></div> Right, because it&#39;s not a derivative of that interface, it&#39;s its ow= n type, defined only inside the function. =C2=A0Yeah, I know it&#39;s confu= sing :)<div><br> <br> <blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1p= x #ccc solid;padding-left:1ex"> =C2=A0That&#39;s weird, because &quot;std.range.InputRange!(int).<u></u>Inp= utRange&quot; doesn&#39;t even<br> look like a type.<br> </blockquote> <br></div> std.range is the module, but I assume you already know that.<br> <br> But one of the coolest things about D templates is the eponymous rule. =C2= =A0That is, if you declare a template, and that template has exactly one me= mber, and that one member is named the same as the template, then x!(y) bec= omes the equivalent of x!(y).x.<br> <br> For example:<br> <br> template t(T)<br> {<br> =C2=A0 class t<br> =C2=A0 {<br> =C2=A0 =C2=A0 =C2=A0T val;<br> =C2=A0 }<br> }<br> <br> t!(int) is equivalent to t!(int).t<br> <br> In other words, a template is a *namespace* for declarations using the temp= late parameters. =C2=A0And in this special case, you can omit the member of= the namespace you are accessing.<br> <br> Then what follows is that:<br> <br> class t(T)<br> {<br> =C2=A0 T val;<br> }<br> <br> is shorthand for the above.<br> <br> But the compiler maintains the namespace.member nomenclature, which is why = you see that in the error message.<br> <br> -Steve<br> </blockquote></div><br></div></div></div></div> --bcaec52e6045b3076304a7902d67--
Jul 08 2011
prev sibling next sibling parent James Fisher <jameshfisher gmail.com> writes:
--bcaec51f9905e6bb1404a79033bf
Content-Type: text/plain; charset=UTF-8

On Fri, Jul 8, 2011 at 4:06 PM, James Fisher <jameshfisher gmail.com> wrote:
 So ... stuff works, but I'm not really sure why one uses function
 templating and the other uses return type inference.  Any answers?

... Wait, brain malfunction; I think I do understand. The type is inferable purely from the function definition in the latter case. --bcaec51f9905e6bb1404a79033bf Content-Type: text/html; charset=UTF-8 Content-Transfer-Encoding: quoted-printable <div class=3D"gmail_quote">On Fri, Jul 8, 2011 at 4:06 PM, James Fisher <sp= an dir=3D"ltr">&lt;<a href=3D"mailto:jameshfisher gmail.com">jameshfisher g= mail.com</a>&gt;</span> wrote:<blockquote class=3D"gmail_quote" style=3D"ma= rgin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;"> So ... stuff works, but I&#39;m not really sure why one uses function templ= ating and the other uses return type inference. =C2=A0Any answers?</blockqu= ote><div><br></div><div>... Wait, brain malfunction; I think I do understan= d. =C2=A0The type is inferable purely from the function definition in the l= atter case.</div> </div> --bcaec51f9905e6bb1404a79033bf--
Jul 08 2011
prev sibling next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Fri, 08 Jul 2011 11:08:14 -0400, James Fisher <jameshfisher gmail.com>  
wrote:

 On Fri, Jul 8, 2011 at 4:06 PM, James Fisher <jameshfisher gmail.com>  
 wrote:
 So ... stuff works, but I'm not really sure why one uses function
 templating and the other uses return type inference.  Any answers?

... Wait, brain malfunction; I think I do understand. The type is inferable purely from the function definition in the latter case.

Yes, the return type is determined by the return statement in the function itself. Note that it would be an error to have two different return types that compiled into the same function. A frequent use of auto is when the return type could be different based on template parameters to the function, or version statements. In these cases, effectively there is only one return type, because only one return statement gets compiled. The reason your getSquares(T)() *call* doesn't work is because the compiler first must instantiate the template, and it doesn't have enough information to do so. Remember that a function template like this: T getSquares(T)() {...} is equivalent to this: template getSquares(T) { T getSquares() {...} } So in fact, the compiler cannot evaluate the inner part of the template until it knows what T is. However, there is a special feature called implicit function template instantiation (IFTI) which allows the compiler to infer the values of T from the function call being made. This means the types of arguments to the function can be used to infer the template parameters. This *only* works for template functions or templates that can be reduced to template functions. So for example: T foo(T)(T t) {return t;} you can call this function via: foo(1); And T will implicitly be assigned int. But since your getSquares function takes no parameters, IFTI cannot be used. Note that the return type does NOT play a role in IFTI. However, you can still use getSquares, just specify the template parameter explicitly: auto sq = getSquares!int(); Another option is to give a default value for T: T getSquares(T = int)() {...} -Steve
Jul 08 2011
prev sibling parent James Fisher <jameshfisher gmail.com> writes:
--90e6ba1ef668a82b8704a791917a
Content-Type: text/plain; charset=UTF-8

On Fri, Jul 8, 2011 at 4:49 PM, Steven Schveighoffer <schveiguy yahoo.com>wrote:

 On Fri, 08 Jul 2011 11:08:14 -0400, James Fisher <jameshfisher gmail.com>
 wrote:

  On Fri, Jul 8, 2011 at 4:06 PM, James Fisher <jameshfisher gmail.com>
 wrote:

 So ... stuff works, but I'm not really sure why one uses function
 templating and the other uses return type inference.  Any answers?

... Wait, brain malfunction; I think I do understand. The type is inferable purely from the function definition in the latter case.

Yes, the return type is determined by the return statement in the function itself. Note that it would be an error to have two different return types that compiled into the same function. A frequent use of auto is when the return type could be different based on template parameters to the function, or version statements. In these cases, effectively there is only one return type, because only one return statement gets compiled. The reason your getSquares(T)() *call* doesn't work is because the compiler first must instantiate the template, and it doesn't have enough information to do so. Remember that a function template like this: T getSquares(T)() {...} is equivalent to this: template getSquares(T) { T getSquares() {...} } So in fact, the compiler cannot evaluate the inner part of the template until it knows what T is. However, there is a special feature called implicit function template instantiation (IFTI) which allows the compiler to infer the values of T from the function call being made. This means the types of arguments to the function can be used to infer the template parameters. This *only* works for template functions or templates that can be reduced to template functions. So for example: T foo(T)(T t) {return t;} you can call this function via: foo(1); And T will implicitly be assigned int. But since your getSquares function takes no parameters, IFTI cannot be used. Note that the return type does NOT play a role in IFTI. However, you can still use getSquares, just specify the template parameter explicitly: auto sq = getSquares!int(); Another option is to give a default value for T: T getSquares(T = int)() {...} -Steve

This all makes sense. Thanks for the comprehensive explanation. :) --90e6ba1ef668a82b8704a791917a Content-Type: text/html; charset=UTF-8 Content-Transfer-Encoding: quoted-printable <div class=3D"gmail_quote">On Fri, Jul 8, 2011 at 4:49 PM, Steven Schveigho= ffer <span dir=3D"ltr">&lt;<a href=3D"mailto:schveiguy yahoo.com">schveiguy= yahoo.com</a>&gt;</span> wrote:<br><blockquote class=3D"gmail_quote" style= =3D"margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;"> On Fri, 08 Jul 2011 11:08:14 -0400, James Fisher &lt;<a href=3D"mailto:jame= shfisher gmail.com" target=3D"_blank">jameshfisher gmail.com</a>&gt; wrote:= <br> <br> <blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1p= x #ccc solid;padding-left:1ex"><div class=3D"im"> On Fri, Jul 8, 2011 at 4:06 PM, James Fisher &lt;<a href=3D"mailto:jameshfi= sher gmail.com" target=3D"_blank">jameshfisher gmail.com</a>&gt; wrote:<br> <blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1p= x #ccc solid;padding-left:1ex"> <br> So ... stuff works, but I&#39;m not really sure why one uses function<br> templating and the other uses return type inference. =C2=A0Any answers?<br> </blockquote> <br> <br></div><div class=3D"im"> ... Wait, brain malfunction; I think I do understand. =C2=A0The type is inf= erable<br> purely from the function definition in the latter case.<br> </div></blockquote> <br> <br> Yes, the return type is determined by the return statement in the function = itself. =C2=A0Note that it would be an error to have two different return t= ypes that compiled into the same function. =C2=A0A frequent use of auto is = when the return type could be different based on template parameters to the= function, or version statements. =C2=A0In these cases, effectively there i= s only one return type, because only one return statement gets compiled.<br=

<br> The reason your getSquares(T)() *call* doesn&#39;t work is because the comp= iler first must instantiate the template, and it doesn&#39;t have enough in= formation to do so. =C2=A0Remember that a function template like this:<br> <br> T getSquares(T)() {...}<br> <br> is equivalent to this:<br> <br> template getSquares(T)<br> {<br> =C2=A0 T getSquares() {...}<br> }<br> <br> So in fact, the compiler cannot evaluate the inner part of the template unt= il it knows what T is. =C2=A0However, there is a special feature called imp= licit function template instantiation (IFTI) which allows the compiler to i= nfer the values of T from the function call being made. =C2=A0This means th= e types of arguments to the function can be used to infer the template para= meters. =C2=A0This *only* works for template functions or templates that ca= n be reduced to template functions.<br> <br> So for example:<br> <br> T foo(T)(T t) {return t;}<br> <br> you can call this function via:<br> <br> foo(1);<br> <br> And T will implicitly be assigned int.<br> <br> But since your getSquares function takes no parameters, IFTI cannot be used= . =C2=A0Note that the return type does NOT play a role in IFTI.<br> <br> However, you can still use getSquares, just specify the template parameter = explicitly:<br> <br> auto sq =3D getSquares!int();<br> <br> Another option is to give a default value for T:<br> <br> T getSquares(T =3D int)() {...}<br> <br> -Steve<br> </blockquote></div><br><div>This all makes sense. =C2=A0Thanks for the comp= rehensive explanation. :)</div> --90e6ba1ef668a82b8704a791917a--
Jul 08 2011