July 20, 2004
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
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
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
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
"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
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
> 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
"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