<div dir="ltr"><div style="font-family:arial,sans-serif;font-size:12.727272033691406px">Following the recent thread "front evaluated multiple time with joiner depending on where extra arg given", I'd like to propose the following addition in std.range :</div>
<div style="font-family:arial,sans-serif;font-size:12.727272033691406px"><br></div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px">The goal is to ensure that a given range's 'front' method is called only once per element, allowing one to handle safely side effects in 'front' methods</div>
<div style="font-family:arial,sans-serif;font-size:12.727272033691406px"><br></div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px">eg use case: lambdas with side effects given to a map/reduce/filter function, etc.</div>
<div style="font-family:arial,sans-serif;font-size:12.727272033691406px"><br></div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px">import std.traits;<br></div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px">
import std.range;</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px">struct CacheFront(R){</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px">  alias T=ElementType!R;</div>
<div style="font-family:arial,sans-serif;font-size:12.727272033691406px">  R a;</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px">  import util.traits;</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px">
  enum isRef=mixin(isLvalue(q{a.front}));</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px">  static if(isRef)</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px">    T* ai;</div>
<div style="font-family:arial,sans-serif;font-size:12.727272033691406px">  else{</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px">    T ai;    </div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px">
    bool isValid=false;</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px">  }</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px">  auto ref front(){</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px">
    //TODO: could also depend on whether front is pure</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px">    static if(isRef){</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px">
      if(ai)</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px">        return *ai;</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px">      else{</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px">
        ai=&a.front;</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px">        return *ai;</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px">      }</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px">
    }</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px">    else{</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px">      if(isValid){</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px">
        return ai;</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px">      }</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px">      else{</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px">
        isValid=true;</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px">        ai=a.front;</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px">        return ai;</div>
<div style="font-family:arial,sans-serif;font-size:12.727272033691406px">      }      </div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px">    }</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px">
  }</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px">  void popFront(){</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px">    a.popFront;</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px">
    static if(isRef)</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px">      ai=null;</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px">    else</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px">
      isValid=false;</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px">  }</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px">  //forward other properties automatically:</div>
<div style="font-family:arial,sans-serif;font-size:12.727272033691406px">  alias a this;</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px">}</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px">
auto cacheFront(R)(R a) if(isInputRange!R){</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px">  return CacheFront!R(a);</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px">
}</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px"><br></div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px">//helper function (should be in phobos' std.traits)</div>
<div style="font-family:arial,sans-serif;font-size:12.727272033691406px"><div>void requireLvalue(T)(ref T);</div><div>string isLvalue(string a){</div><div><span style="white-space:pre-wrap">    </span>return `__traits(compiles, requireLvalue(`~a~`))`;</div>
<div>}</div></div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px"><br></div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px">void main(){</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px">
  import std.algorithm;</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px">  import std.array;</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px">  {</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px">
    //checks that it calls front only once per element</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px">    uint counter;</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px">
    auto b=[1,2,3].map!((a){counter++; return [a];}).cacheFront.joiner.array;</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px">    assert(counter==3);</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px">
    assert(b==[1,2,3]);</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px">  }</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px">  {</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px">
    int counter=0;</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px">    auto b=[1,2,3].map!((a){counter++; return [a];}).joiner.array;</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px">
    assert(counter==6);</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px">  }</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px"> {</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px">
    //checks that it works with ref front</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px">    auto a0=[1,2,3];</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px">    auto ref fun0(ref int a){a=0; return a;}</div>
<div style="font-family:arial,sans-serif;font-size:12.727272033691406px">    auto b=a0. cacheFront.map!fun0.array;</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px">    assert(b==[0,0,0]);</div>
<div style="font-family:arial,sans-serif;font-size:12.727272033691406px">    assert(a0==[0,0,0]);</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px"><br></div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px">
    //checks that it forwards properties of range:</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px">    assert([1,2,3]. cacheFront.length==3);</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px">
  }</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px">}</div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px"><br></div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px">
<br></div><div style="font-family:arial,sans-serif;font-size:12.727272033691406px">And a side question: is there a way to denote that a lambda can return by ref?  </div></div>