www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.dtl - Implementing and overloading collect()

reply "Matthew" <admin.hat stlsoft.dot.org> writes:
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?
Jul 19 2004
parent reply Gold Dragon <dragonwing dragonu.net> writes:
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.
Jul 21 2004
parent "Matthew" <admin.hat stlsoft.dot.org> writes:
"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
Jul 23 2004