Can we get rid of opApply?
Steven Schveighoffer
schveiguy at yahoo.com
Mon Jan 19 13:17:06 PST 2009
"Andrei Alexandrescu" wrote
> Steven Schveighoffer wrote:
>> When looking at ranges, it seems like a much better model for iteration
>> than opApply. It seems like it could be a whole replacement for opApply.
>> But when looking at the current usage of opApply, there are some holes.
>>
>> foreach(i, x; range)
>> {
>> }
>>
>> What exactly happens? Do you have to return a tuple from a range with
>> head()?
>
> One possibility I'd discussed with Walter is that for the usage above, the
> compiler asks for the .key property in addition to .head. If more keys are
> specified, .key1, .key2... are required.
I'd say labeling them "key" would be slightly biased. The arguments to
opApply might not always be considered a key. I'd label them .head1,
.head2, etc.
Also, how do you recreate this case:
struct S
{
int opApply(int delegate(ref int idx, ref int v) dg) {...}
int opApply(int delegate(ref string k, ref int v) dg) {...}
int opApply(int delegate(ref int idx, ref string k, ref int v) dg) {...}
}
Think of S as a container that can look up values by index or by string
(like a sorted dictionary).
> Probably an array would be a nicer solution.
I'm interested to hear what you mean by that.
>> Also, another thing that was nice about opApply, if you had multiple ways
>> to iterate over an aggregate, you simply altered your arguments to
>> foreach. How can this be implemented with ranges?
>>
>> class Aggregate
>> {
>> int opApply(int delegate(ref int idx, ref int value) dg) {...}
>> int opApply(int delegate(ref int value) dg) {...}
>> }
>>
>> Aggregate A = new Aggregate;
>> foreach(i, ref x; A) {...}
>> foreach(x; A) {...}
>
> Keys will take care of that too. The "ref" thing will generate different
> code by taking the address of head (not sure if Walter implemented that).
You mean taking the address of the return value from head? Or using a
delegate? I'm not sure what you mean... I'd be wary of performance if you
mean take a delegate.
>
>> Maybe ranges need some more functionality to do this. I can't see how to
>> do it with Tuples, as you'd have to be able to overload head() based on
>> return value. Or if a proposed opRange is supported from Aggregate
>> (opRange is called if it exists, otherwise if the aggregate is a range
>> use that, otherwise look for opApply), you'd have to overload the range
>> type returned based on usage.
>
> Yes, I'm afraid type deduction will be harmed with ranges.
BAD BAD BAD! I love being able to do type deduction in foreach... Not
having that would be a real hard pill to swallow...
>
>> The only thing I could think of is to change head and toe to take
>> reference parameters instead of using the return value, although that's
>> ugly. Maybe it could be supported in addition to returning a value?
>
> [snip]
>
>> This is ugly, and requires some compiler magic, but do you see another
>> way to do it? I didn't know if "ref ref" would work, so that's why I use
>> pointers instead. Since ref is a storage class, I don't know if the
>> compiler would overload anyways...
>
> One simple solution to the overloading by return type would be to have
> head be a template. Then if you say:
>
> foreach (int e; range) {}
>
> the corresponding assignment for e will be:
>
> int e = __r.head!(int)();
>
> There are a few more wrinkles to fill with Botox though :o).
Yuck. I'd much rather see this implemented with ref parameters. It seems
like a waste to have to use templates for overloading in my range struct
when a perfectly good type system is available. Just my opinion.
-Steve
More information about the Digitalmars-d
mailing list