Thread overview
Implementing and overloading collect()
Jul 20, 2004
Matthew
Jul 21, 2004
Gold Dragon
Jul 23, 2004
Matthew
July 20, 2004
I've got the select()/reject() stuff happening pretty nicely, and composing
two levels works fine. (>2 levels compiles, but is causing OPTLINK to die an
unhappy little death.)

Because of the fact that overloading of templates and non-templates is not supported, and also that overloading within member templates is not (yet) supported, these two methods look, for a given container (or range!), like the following:

        MatchedRange!(range_type, Not!(match_fn_pred_type))
reject(match_function_type d)
        {
            return new MatchedRange!(range_type,
Not!(match_fn_pred_type))(opSlice(), new Not!(match_fn_pred_type)(new
match_fn_pred_type(d)));
        }

        MatchedRange!(range_type, Not!(match_dg_pred_type))
reject(match_delegate_type d)
        {
            return new MatchedRange!(range_type,
Not!(match_dg_pred_type))(opSlice(), new Not!(match_dg_pred_type)(new
match_dg_pred_type(d)));
        }

        template reject0(P) { final MatchedRange!(range_type, Not!(P))
reject0()
        {
            return new MatchedRange!(range_type, Not!(P))(opSlice(), new
Not!(P)(new P()));
        }}
        template reject1(P) { final MatchedRange!(range_type, Not!(P))
reject1(P p)
        {
            return new MatchedRange!(range_type, Not!(P))(opSlice(), new
Not!(P)(p));
        }}

The first two are used by just passing the address of either a function, or a delegate. The third and fourth are used by instantiating with the functor template, (Note: I'm going to use the word functor in DTL, so as to disambiguate from "function".), as in:

        foreach(int i; cont.select1!(DivisibleBy)(new
DivisibleBy(3)).reject0!(IsEven))
        {
            printf("%d ", i);
        }

I've keeping the 0 and 1 suffixes for the moment, hence select0!(), reject1!(). I am hoping to persuade Walter that implicit template properties will be supported soon, at which point the 0 and 1 forms will become "_with", as in:

        foreach(int i; cont.select_with!(DivisibleBy)(new
DivisibleBy(3)).reject_with!(IsEven))
        {
            printf("%d ", i);
        }

So, I've pretty much got select() and reject() happening. The next challenge
is collect() (aka transform). As with select()/reject(), I want to provide
forms for function, delegate and functor. The latter is already supported,
and looks like this:

        template collect0(F, T2 = value_type) { final
TransformedRange!(range_type, F, T2) collect0()
        {
            return new TransformedRange!(range_type, F, T2)(opSlice(), new
F());
        }}
        template collect1(F, T2 = value_type) { final
TransformedRange!(range_type, F, T2) collect1(F f = new F())
        {
            return new TransformedRange!(range_type, F, T2)(opSlice(), f);
        }}

with client code such as:

        printf("\ncollect()-ing the numbers, with int_doubler\n");
        foreach(int i; cont.collect!(IntDoubler)())
        {
            printf("%d ", i);
        }
        printf("\n");

But here's the rub with the function/delegate forms. Providing non-template function/delegate forms for select()/reject() was straightforward - hah! - well, is straightforward now I've done it, because they take predicates, and the return type of a predicate is bool. However, with collect(), the function/delegate transforms the current value to a new value, which may potentially be of a new type: note the T2 template parameter in the above template collect0/1() forms. This is the "issue". I can implement a non-template form easily as long as the new value's type is the same as the value_type of the container (or range). But we would clearly want to transform from one type to another in the general case, and it'd be nice to support that for functions and delegates, as well as functors.

So, my question is:

1. Shall I provide same-type only collect() methods for function/delegate forms? This would mean that when you want to transform type as well/instead of value, you must use the functor form.

2. Shall I provide member-template only collect() methods for function/delegate forms, as well as for the functor form? This would mean that one would always have to stipulate the tranformed type, even when its the same as the container(/range)'s value_type?

3. Shall I provide both forms, using different names?

4. Does anyone know any neat technique by which the result type (and parameter types) can be deduce without templates?





July 21, 2004
So you are saying that when overloading of Templates and Non-Templates and the other thing you were talking about happen we would be able to use just select() and not select1 or reject1?

I can see how describing whether or not to use 0, 1, 2, etc would be difficult for the novice, aka, me.
July 23, 2004
"Gold Dragon" <dragonwing@dragonu.net> wrote in message news:cdmit8$319o$1@digitaldaemon.com...
> So you are saying that when overloading of Templates and Non-Templates and the other thing you were talking about happen we would be able to use just select() and not select1 or reject1?

That would be my hope

> I can see how describing whether or not to use 0, 1, 2, etc would be difficult for the novice, aka, me.

Well, they're only there as space fillers until the library is in a more-prepared state and, hopefully, the language changes somewhat