View mode: basic / threaded / horizontal-split · Log in · Help
December 09, 2007
opApply and const
I mentioned it in another thread but I just wanted to confirm it.
Am I right in thinking that if we want to have user types act like 
built-in containers w.r.t iteration in D2 then we need to implement 12 
different versions of opApply?!

Namely:

// plain vanilla
int opApply(int delegate(ref T)) {...}
const int opApply(int delegate(ref const T)) {...}
invariant int opApply(int delegate(ref invariant T)) {...}

// with counter
int opApply(int delegate(ref size_t, ref T)) {...}
const int opApply(int delegate(ref size_t, ref const T)) {...}
invariant int opApply(int delegate(ref size_t, ref invariant T)) {...}

// backwards
int opApplyReverse(int delegate(ref T)) {...}
const int opApplyReverse(int delegate(ref const T)) {...}
invariant int opApplyReverse(int delegate(ref invariant T)) {...}

// backwards with counter
int opApplyReverse(int delegate(ref size_t, ref T)) {...}
const int opApplyReverse(int delegate(ref size_t, ref const T)) {...}
invariant int opApplyReverse(int delegate(ref size_t, ref invariant T)) 
{...}

That's a lot of opApply!  I was already mildly annoyed by the four 
needed without const.  But with both const (and invariant) it just seems 
downright silly.

--bb
December 09, 2007
Re: opApply and const
Bill Baxter wrote:
> I mentioned it in another thread but I just wanted to confirm it.
> Am I right in thinking that if we want to have user types act like 
> built-in containers w.r.t iteration in D2 then we need to implement 12 
> different versions of opApply?!
> 
> Namely:
> 
> // plain vanilla
> int opApply(int delegate(ref T)) {...}
> const int opApply(int delegate(ref const T)) {...}
> invariant int opApply(int delegate(ref invariant T)) {...}
> 
> // with counter
> int opApply(int delegate(ref size_t, ref T)) {...}
> const int opApply(int delegate(ref size_t, ref const T)) {...}
> invariant int opApply(int delegate(ref size_t, ref invariant T)) {...}
> 
> // backwards
> int opApplyReverse(int delegate(ref T)) {...}
> const int opApplyReverse(int delegate(ref const T)) {...}
> invariant int opApplyReverse(int delegate(ref invariant T)) {...}
> 
> // backwards with counter
> int opApplyReverse(int delegate(ref size_t, ref T)) {...}
> const int opApplyReverse(int delegate(ref size_t, ref const T)) {...}
> invariant int opApplyReverse(int delegate(ref size_t, ref invariant T)) 
> {...}
> 
> That's a lot of opApply!  I was already mildly annoyed by the four 
> needed without const.  But with both const (and invariant) it just seems 
> downright silly.
> 
> --bb

It's not just opApply; any function would need to be written three times 
for accessing constant data in a possibly mutable class.
December 09, 2007
Re: opApply and const
On 12/9/07, Bill Baxter <dnewsgroup@billbaxter.com> wrote:
> const int opApply(int delegate(ref const T)) {...}

And "ref const T" seems a bit of an oxymoron anyway.

I can bring it down to eight. You shouldn't have to deal with
invariant classes. These can't really exist in D, since

   invarant C = new C;

will fail to compile, and there is no "inew".

But yeah - eight versions of the same function is too much. Is there
any way we can narrow it down to one? (One that actually works, in all
eight cases?)
December 09, 2007
Re: opApply and const
Janice Caron wrote:
>     invarant C = new C;
> 
> will fail to compile, and there is no "inew".

invariant C = cast(invariant) new C();
December 09, 2007
Re: opApply and const
On 12/9/07, Robert Fraser <fraserofthenight@gmail.com> wrote:
> Janice Caron wrote:
> >     invarant C = new C;
> >
> > will fail to compile, and there is no "inew".
>
> invariant C = cast(invariant) new C();

I didn't forget that, I just didn't see the point of it.

What I did forget, though, is invariant structs. Now they do make
sense! And surely opApply has to work for those, too.

So we're back up to twelve again!
December 09, 2007
Re: opApply and const
Bill Baxter wrote:
> I mentioned it in another thread but I just wanted to confirm it.
> Am I right in thinking that if we want to have user types act like
> built-in containers w.r.t iteration in D2 then we need to implement 12
> different versions of opApply?!
> 
> Namely:
> 
> [snip]
> 
> That's a lot of opApply!  I was already mildly annoyed by the four
> needed without const.  But with both const (and invariant) it just seems
> downright silly.
> 
> --bb

There's really no need for the counter versions.  Just solve this the
same way Python did: with a wrapper.  Admittedly, this doesn't seem to
work for more than one argument (foreach appears to dislike tuples for
arguments), but it illustrates the general concept.

	-- Daniel

module enumerate;

import std.stdio;
import std.traits;

struct Enumerate(T)
{
   private
   {
       T source;
       alias ParameterTypeTuple!(typeof(T.opApply))[0] opApply_arg;
       alias ParameterTypeTuple!(opApply_arg) opApply_type;
   }

   int opApply(int delegate(ref size_t, opApply_type) dg)
   {
       int result = 0;
       size_t i = 0;
       foreach( x ; source )
       {
           if( (result=dg(i,x)) != 0 ) break;
           ++i;
       }
       return result;
   }
}

Enumerate!(T) enumerate(T)(T source)
{
   return Enumerate!(T)(source);
}

class Foo
{
   static const words = ["On"[],"a","Sunday,","riding","my","bike"];

   int opApply(int delegate(ref char[]) dg)
   {
       int result = 0;
       foreach( word ; words )
           if( (result=dg(word)) != 0 ) break;
       return result;
   }
}

void main()
{
   foreach( word ; new Foo )
       writef("%s ",word);
   writefln("");

   writefln("");

   foreach( i,word ; enumerate(new Foo) )
       writefln("[%s] %s", i, word);
}
December 09, 2007
Re: opApply and const
My apologies.  It *does* actually support arbitrary opApply()s.  What
probably *doesn't* support are types with more than one opApply.  Can we
get a list of overloads with D 2.0 yet?

	-- Daniel

module enumerate;

import std.stdio;
import std.traits;

struct Enumerate(T)
{
   private
   {
       T source;
       alias ParameterTypeTuple!(typeof(T.opApply))[0] opApply_arg;
       alias ParameterTypeTuple!(opApply_arg) opApply_type;
   }

   int opApply(int delegate(ref size_t, opApply_type) dg)
   {
       int result = 0;
       size_t i = 0;

       foreach( ref opApply_type x ; source )
       {
           if( (result=dg(i,x)) != 0 ) break;
           ++i;
       }
       return result;
   }
}

Enumerate!(T) enumerate(T)(T source)
{
   return Enumerate!(T)(source);
}

class Foo
{
   static const words = ["On"[],"a","Sunday,","riding","my","bike"];

   int opApply(int delegate(ref char[]) dg)
   {
       int result = 0;
       foreach( word ; words )
           if( (result=dg(word)) != 0 ) break;
       return result;
   }
}

class Bar
{
   int opApply(int delegate(ref real, ref char[]) dg)
   {
       // Nasty code:
       real r; char[] d;
       r = 3.14159;    d = "pi"; dg(r,d);
       r = 3.0;        d = "pi (according to the Bible)"; dg(r,d);
       r = 42.0;       d = "meaning of life"; dg(r,d);
       r = real.nan;   d = "how much wood would a wood chuck chuck?";
dg(r,d);
       return 0;
   }
}

void main()
{
   foreach( word ; new Foo )
       writef("%s ",word);
   writefln("");

   writefln("");

   foreach( i,word ; enumerate(new Foo) )
       writefln("[%s] %s", i, word);

   writefln("");

   foreach( r,desc ; new Bar )
       writefln("%s: %s", r, desc);

   writefln("");

   foreach( i,r,desc ; enumerate(new Bar) )
       writefln("[%s] %s: %s", i, r, desc);
}
December 09, 2007
Re: opApply and const
Daniel Keep wrote:
> My apologies.  It *does* actually support arbitrary opApply()s.  What
> probably *doesn't* support are types with more than one opApply.  Can we
> get a list of overloads with D 2.0 yet?
> 
> 	-- Daniel

In the general case: no.
If you're only concerned about the virtual ones: yes, with 
__traits(getVirtualFunctions). (I think that's it; I always forget what 
it is exactly.)


> module enumerate;
> 
> import std.stdio;
> import std.traits;
> 
> struct Enumerate(T)
> {
>     private
>     {
>         T source;
>         alias ParameterTypeTuple!(typeof(T.opApply))[0] opApply_arg;
>         alias ParameterTypeTuple!(opApply_arg) opApply_type;
>     }
> 
>     int opApply(int delegate(ref size_t, opApply_type) dg)
>     {
>         int result = 0;
>         size_t i = 0;
> 
>         foreach( ref opApply_type x ; source )
>         {
>             if( (result=dg(i,x)) != 0 ) break;
>             ++i;
>         }
>         return result;
>     }
> }
> 
> Enumerate!(T) enumerate(T)(T source)
> {
>     return Enumerate!(T)(source);
> }
> 
> class Foo
> {
>     static const words = ["On"[],"a","Sunday,","riding","my","bike"];
> 
>     int opApply(int delegate(ref char[]) dg)
>     {
>         int result = 0;
>         foreach( word ; words )
>             if( (result=dg(word)) != 0 ) break;
>         return result;
>     }
> }
> 
> class Bar
> {
>     int opApply(int delegate(ref real, ref char[]) dg)
>     {
>         // Nasty code:
>         real r; char[] d;
>         r = 3.14159;    d = "pi"; dg(r,d);
>         r = 3.0;        d = "pi (according to the Bible)"; dg(r,d);
>         r = 42.0;       d = "meaning of life"; dg(r,d);
>         r = real.nan;   d = "how much wood would a wood chuck chuck?";
> dg(r,d);
>         return 0;
>     }
> }
> 
> void main()
> {
>     foreach( word ; new Foo )
>         writef("%s ",word);
>     writefln("");
> 
>     writefln("");
> 
>     foreach( i,word ; enumerate(new Foo) )
>         writefln("[%s] %s", i, word);
> 
>     writefln("");
> 
>     foreach( r,desc ; new Bar )
>         writefln("%s: %s", r, desc);
> 
>     writefln("");
> 
>     foreach( i,r,desc ; enumerate(new Bar) )
>         writefln("[%s] %s: %s", i, r, desc);
> }
December 09, 2007
Re: opApply and const
Daniel Keep wrote:
> My apologies.  It *does* actually support arbitrary opApply()s.  What
> probably *doesn't* support are types with more than one opApply.  Can we
> get a list of overloads with D 2.0 yet?

I like it (no surprise since I also like Python).
How about reverse?  Can you cook up a reversed() template that would use 
an opApplyReverse if it exists or else forward iterate into a buffer and 
reverse iterate over that?  Or maybe creating a big temp buffer silently 
isn't such a hot idea...
December 10, 2007
Re: opApply and const
Bill Baxter wrote:
> Daniel Keep wrote:
>> My apologies.  It *does* actually support arbitrary opApply()s.  What
>> probably *doesn't* support are types with more than one opApply.  Can we
>> get a list of overloads with D 2.0 yet?
> 
> I like it (no surprise since I also like Python).
> How about reverse?  Can you cook up a reversed() template that would use
> an opApplyReverse if it exists or else forward iterate into a buffer and
> reverse iterate over that?  Or maybe creating a big temp buffer silently
> isn't such a hot idea...

Well, this is how Python does it, I believe.  The position there appears
to be: better to be possible and inefficient than not possible at all.

Really, I think it's somewhat surprising that D doesn't have *any*
iteration tools whatsoever.  If I weren't already so busy with other
things, I'd be tempted to write some myself.  And there's always the
chance that downs has written stuff already (that no one else can read
without screaming in pain.)  ;)

Still, I think one of the biggest hurdles to writing a good iterator
toolkit is how opApply is implemented in D.  Because of the callback
design, you can't do anything with resumable iterators, you can't do
multiple iterations in lockstep... it's a bit of a pity that opApply
is so firmly entrenched in the language.  Oh well; I suppose there's
always D 3.0.  :)

	-- Daniel
« First   ‹ Prev
1 2
Top | Discussion index | About this forum | D home