View mode: basic / threaded / horizontal-split · Log in · Help
July 20, 2004
Filter composition is here. :-)
Just wanted to let the faithful (and the faithless) know that I'm getting
there. I've just got the following code to compile:

   foreach(int i; cont.select1!(DivisibleBy)(new
DivisibleBy(3)).reject(&isEven))
   {
       printf("%d ", i);
   }
   printf("\n");

yielding:

   -9 -3 3 9

from a List containing [-20, 20)

DivisibleBy is a functor, and isEven is a plain function
July 20, 2004
Re: Filter composition is here. :-)
Hmm, just had an idea. Can I use a class (static) opCall on a functor to create
it, without clashing with the member (non-static) opCall?

It's only a small saving, but it'd trim

   cont.select1!(DivisibleBy)(new DivisibleBy(3)).reject(&isEven))

down to

   cont.select1!(DivisibleBy)(DivisibleBy(3)).reject(&isEven))

Ah, if only we have implicit instantiation ... ;)

"Matthew" <admin.hat@stlsoft.dot.org> wrote in message
news:cdi01n$vo4$1@digitaldaemon.com...
> Just wanted to let the faithful (and the faithless) know that I'm getting
> there. I've just got the following code to compile:
>
>     foreach(int i; cont.select1!(DivisibleBy)(new
> DivisibleBy(3)).reject(&isEven))
>     {
>         printf("%d ", i);
>     }
>     printf("\n");
>
> yielding:
>
>     -9 -3 3 9
>
> from a List containing [-20, 20)
>
> DivisibleBy is a functor, and isEven is a plain function
>
>
July 20, 2004
Re: Filter composition is here. :-)
Is there a description/spec somewhere for select, reject, etc? What are the
use cases? What are the advantages/disadvantages of using them as opposed to
foreach(int i, cont) {
 if (!isEven(i) && (i%3 == 0))
   printf("%d ",i);
}
If these things are delaying the rest of DTL and they are driving fairly big
compiler changes I'd like to know more about them. Call me a party-pooper
but I'm not convinced right now that they are that big of a deal. Personally
I find the basic foreach to be much more readable.

"Matthew" <admin.hat@stlsoft.dot.org> wrote in message
news:cdi01n$vo4$1@digitaldaemon.com...
> Just wanted to let the faithful (and the faithless) know that I'm getting
> there. I've just got the following code to compile:
>
>     foreach(int i; cont.select1!(DivisibleBy)(new
> DivisibleBy(3)).reject(&isEven))
>     {
>         printf("%d ", i);
>     }
>     printf("\n");
>
> yielding:
>
>     -9 -3 3 9
>
> from a List containing [-20, 20)
>
> DivisibleBy is a functor, and isEven is a plain function
>
>
July 20, 2004
Re: Filter composition is here. :-)
In article <cdj7b4$1h6f$1@digitaldaemon.com>, Ben Hinkle says...
>
>Is there a description/spec somewhere for select, reject, etc? What are the
>use cases? What are the advantages/disadvantages of using them as opposed to
> foreach(int i, cont) {
>  if (!isEven(i) && (i%3 == 0))
>    printf("%d ",i);
> }
>If these things are delaying the rest of DTL and they are driving fairly big
>compiler changes I'd like to know more about them. Call me a party-pooper
>but I'm not convinced right now that they are that big of a deal. Personally
>I find the basic foreach to be much more readable.

It might actually be kind of nice if we could do something like this:

int main()
{
int[char[]] map;
map["a"] = 1;
map["b"] = 2;
map["c"] = 3;
foreach( int value; map["a".."b"] )
{
printf( "%d\n", value );
}
return 0;
}

The opSlice extension would largely remove the need for this select() method.


Sean
July 20, 2004
Re: Filter composition is here. :-)
"Sean Kelly" <sean@f4.ca> wrote in message
news:cdjgfc$1li3$1@digitaldaemon.com...
> In article <cdj7b4$1h6f$1@digitaldaemon.com>, Ben Hinkle says...
> >
> >Is there a description/spec somewhere for select, reject, etc? What are
the
> >use cases? What are the advantages/disadvantages of using them as opposed
to
> > foreach(int i, cont) {
> >  if (!isEven(i) && (i%3 == 0))
> >    printf("%d ",i);
> > }
> >If these things are delaying the rest of DTL and they are driving fairly
big
> >compiler changes I'd like to know more about them. Call me a party-pooper
> >but I'm not convinced right now that they are that big of a deal.
Personally
> >I find the basic foreach to be much more readable.
>
> It might actually be kind of nice if we could do something like this:
>
> int main()
> {
> int[char[]] map;
> map["a"] = 1;
> map["b"] = 2;
> map["c"] = 3;
> foreach( int value; map["a".."b"] )
> {
> printf( "%d\n", value );
> }
> return 0;
> }
>
> The opSlice extension would largely remove the need for this select()
method.
>
>
> Sean

Associative arrays don't have any defined ordering to the entries - which I
assume is what you are requesting. Using the C++ terminology a "map" is a
sorted associative array. In the "minimal template library" I just started
your code would work fine if map is declared as type Map!(char[].int)
instead of int[char[]]. Eventually I'd also like to add the equivalent to
Java's LinkedHashMap, which is a hashtable that uses the insertion order for
slicing and foreach (the usual Map implementation use trees which have
O(log(n)) behavior instead of a hashtable's O(1)).

One wrinkle about slicing with keys: the slice includes the last key. This
contrasts with the usual D array slicing behavior where x[1..5] doesn't
include x[5] in the slice. So your example above would print 1 and 2. I went
with this behavior since
1) it would be a pain for users to have to get the next key after the last
one in the slice and
2) what is the key that means "one after the last key in the map?"
For slicing Lists and Maps I went with the rule that any integer slicing
uses the regular D style of excluding the right endpoint but for non-integer
slicing it includes the right endpoint.
July 20, 2004
Re: Filter composition is here. :-)
In article <cdjmbj$1o2i$1@digitaldaemon.com>, Ben Hinkle says...
>
>
>"Sean Kelly" <sean@f4.ca> wrote in message
>news:cdjgfc$1li3$1@digitaldaemon.com...
>> In article <cdj7b4$1h6f$1@digitaldaemon.com>, Ben Hinkle says...
>> >
>> >Is there a description/spec somewhere for select, reject, etc? What are
>the
>> >use cases? What are the advantages/disadvantages of using them as opposed
>to
>> > foreach(int i, cont) {
>> >  if (!isEven(i) && (i%3 == 0))
>> >    printf("%d ",i);
>> > }
>> >If these things are delaying the rest of DTL and they are driving fairly
>big
>> >compiler changes I'd like to know more about them. Call me a party-pooper
>> >but I'm not convinced right now that they are that big of a deal.
>Personally
>> >I find the basic foreach to be much more readable.
>>
>> It might actually be kind of nice if we could do something like this:
>>
>> int main()
>> {
>> int[char[]] map;
>> map["a"] = 1;
>> map["b"] = 2;
>> map["c"] = 3;
>> foreach( int value; map["a".."b"] )
>> {
>> printf( "%d\n", value );
>> }
>> return 0;
>> }
>>
>> The opSlice extension would largely remove the need for this select()
>method.
>>
>>
>> Sean
>
>Associative arrays don't have any defined ordering to the entries - which I
>assume is what you are requesting. Using the C++ terminology a "map" is a
>sorted associative array. In the "minimal template library" I just started
>your code would work fine if map is declared as type Map!(char[].int)
>instead of int[char[]].

Yup.  I had thought that the implementation might be something like:

int[] opSlice( char[] from, char[] to )
{
char[] keys = map.keys;
keys.sort();
// binary search for 'from'
// binary search for 'to'
// construct and return the requested range [from..to]
}

The obvious problem is that the range wouldn't be a slice of the actual map, but
rather a copy.  And sadly, I can't think of an easy way around this.

>One wrinkle about slicing with keys: the slice includes the last key. This
>contrasts with the usual D array slicing behavior where x[1..5] doesn't
>include x[5] in the slice. So your example above would print 1 and 2.

Good point.  And there's no easy way around this for associative arrays.

>I went with this behavior since
>1) it would be a pain for users to have to get the next key after the last
>one in the slice and
>2) what is the key that means "one after the last key in the map?"

Yup.  Without begin and end properties we're kind of stuck in this regard.  And
I guess since the built-in contaners are really hash maps, asking for a sorted
range is kind of silly anyway.  And I suppose we could get away with something
like this for a tree-based map:

class Map {
size_t length();
key_type key( int pos );
value_type value( int pos );
value_type[] opSlice( int b, int e );
}

Thus faking it a bit by using indexes as iterators.


Sean
July 20, 2004
Re: Filter composition is here. :-)
> Yup.  I had thought that the implementation might be something like:
>
> int[] opSlice( char[] from, char[] to )
> {
> char[] keys = map.keys;
> keys.sort();
> // binary search for 'from'
> // binary search for 'to'
> // construct and return the requested range [from..to]
> }
>
> The obvious problem is that the range wouldn't be a slice of the actual
map, but
> rather a copy.  And sadly, I can't think of an easy way around this.

Actually as I have it now the slice of a Map!(K,V) has type Map!(K,V). A Map
has a pointer to the root, a left and right node pointer and a compare
function. This is a pretty big struct but I think it is worth it. The
relevant parts of Map are:

struct Map(K,V) {
Node!(K,V) root, begin, end;
CompareFcn cmp;
Map opSlice(K a, K b) {
  Map res;
   ... look up the node for a and b and fill in res ...
   return res;
 }
 int opApply(int delegate(inout V val) dg) {
   ... loop from this.begin to this.end (with null checks) and apply dg ...
 }
}

I also have opSlice and opIndex with integer indices but it is slower since
to find the Nth node it crawls over the tree from left to right.

> >One wrinkle about slicing with keys: the slice includes the last key.
This
> >contrasts with the usual D array slicing behavior where x[1..5] doesn't
> >include x[5] in the slice. So your example above would print 1 and 2.
>
> Good point.  And there's no easy way around this for associative arrays.
>
> >I went with this behavior since
> >1) it would be a pain for users to have to get the next key after the
last
> >one in the slice and
> >2) what is the key that means "one after the last key in the map?"
>
> Yup.  Without begin and end properties we're kind of stuck in this regard.
And
> I guess since the built-in contaners are really hash maps, asking for a
sorted
> range is kind of silly anyway.  And I suppose we could get away with
something
> like this for a tree-based map:
>
> class Map {
> size_t length();
> key_type key( int pos );
> value_type value( int pos );
> value_type[] opSlice( int b, int e );
> }
>
> Thus faking it a bit by using indexes as iterators.
>
>
> Sean
>
>
July 30, 2004
Re: Filter composition is here. :-)
"Ben Hinkle" <bhinkle@mathworks.com> wrote in message news:cdj7b4$1h6f$1@digitaldaemon.com...
> Is there a description/spec somewhere for select, reject, etc? What are the
> use cases? What are the advantages/disadvantages of using them as opposed to
>  foreach(int i, cont) {
>   if (!isEven(i) && (i%3 == 0))
>     printf("%d ",i);
>  }


I've borrowed the terminology from Ruby. I don't really care what they're called in the long run, just using them for
now.

> If these things are delaying the rest of DTL and they are driving fairly big
> compiler changes I'd like to know more about them. Call me a party-pooper
> but I'm not convinced right now that they are that big of a deal. Personally
> I find the basic foreach to be much more readable.

You're right, and I intend to release 0.1 with minimal bells and whistles this weekend.


>
> "Matthew" <admin.hat@stlsoft.dot.org> wrote in message
> news:cdi01n$vo4$1@digitaldaemon.com...
> > Just wanted to let the faithful (and the faithless) know that I'm getting
> > there. I've just got the following code to compile:
> >
> >     foreach(int i; cont.select1!(DivisibleBy)(new
> > DivisibleBy(3)).reject(&isEven))
> >     {
> >         printf("%d ", i);
> >     }
> >     printf("\n");
> >
> > yielding:
> >
> >     -9 -3 3 9
> >
> > from a List containing [-20, 20)
> >
> > DivisibleBy is a functor, and isEven is a plain function
> >
> >
>
>
Top | Discussion index | About this forum | D home