Any chance to call Tango as Extended Standard Library

Jason House jason.james.house at gmail.com
Mon Jan 19 12:34:20 PST 2009


Andrei Alexandrescu wrote:

> Jason House wrote:
>> Andrei Alexandrescu wrote:
>> 
>>> Speed is a small part of the equation, in fact a perk only. Ranges
>>> are composable; you can combine them to e.g. do parallel iteration
>>> over two ranges. Ranges really open std.algorithm to all data
>>> structures. I find opApply incredibly obtuse and fostering bad
>>> design. I wish it goes away.
>> 
>> I'd really hate to see opApply go away.  I'm glad Walter says it's
>> sticking around ;)
> 
> I know. Its popularity is part of what makes it dangerous. It's to good
> programming what fast food is to food :o).
> 
>> opApply is really nice in how *simple* it is to write.  I think it's
>> possible to use druntime's fibers to convert an opApply
>> implementation into a range implementation.  It'd be an interesting
>> challenge to write a templated struct that handles all of this.  Once
>> that is done, maybe someone could discuss using Fibers to implement
>> opApply in D2.  I suspect the code inside an opApply would only
>> change a little bit and it'd allow iteration over multiple "ranges"
>> at the same time.
> 
> But that's making the mythical bear dance. Iterating over multiple
> ranges is only one example. How do you feed one range to another range
> with opApply?
> 
> At the end of the day, if what you want is to iterate, you need to
> define what the state of iteration is, how to make a step, and how to
> get to the current element being iterated. That is a good design, not
> opApply and fibers!
> 
> 
> Andrei

Are you saying that nobody should ever use coroutines?  A coroutine version of opApply keeps the state of iteration as part of the natural flow of making steps and getting the current element being iterated.  Let's look at various implementation examples:

current opApply style:

int opApply(int delegate( ref T ) dg){
  int unknown;
  foreach(i; 0..length){
    unknown = dg(arr[i]);
    if (unknown != 0)
      return unknown;
  }
  return 0;
}

With coroutine:

void iterateOverArray(T)(T[] arr){
  foreach (i; 0..arr.length)
    yield(arr[i]);
}

... or maybe something more complex like the following is required?

void iterateOverArray(T)(T[] arr){
  foreach (i; 0..arr.length){
    yield!("empty") = false;
    yield!("next") = arr[i];
  }
  yield!("empty") = true;
}


A range-based struct:

struct arrayIterator(T){
  int _i;
  T[] _arr;
  this(T[] arr){
    arr = _arr;
  }
  T next(){
    return arr[i++];
  }
  bool empty{
    return i<_arr.length;
  }
}

Here are the line counts for the above implementations:
current opApply style: 9
coroutine with implied empty: 4
coroutine with explicit empty: 7
range-based: 13

Which one would D users want to write?  Personally, I want the coroutine with implied empty.  I could see having to explicitly state empty or at least specify when it changes.  If the above examples don't convince you that D should consider allowing alternate implementations to basic range structs, then I'll stop trying to convince you.  



More information about the Digitalmars-d mailing list