Voldemort type is fine idiom, but which cannot control the *nested-ness* of inner struct completely, with current dmd.
I think 'static nested template struct' should work.
template map(alias pred) {
auto map(Range)(Range input) {
static struct Result(alias pred) {
Range input = r;
this(Range r) { input = r; }
auto empty() { return r.empty; }
auto front() { return pred(r.front); }
void popFront() { r.popFront(); }
}
return Result!pred(input);
}
}
In above code:
1. the struct Result should not require the context of map function.
2. If pred requires a context, Result is implicitly treated as nested struct.
3. And Result can access the type 'Range' in accordance with lexical scope rule.
Comment #1 by clugdbug — 2012-07-30T08:34:35Z
Do you mean, that the context pointer would be the frame pointer of the function which made the call? (rather than the frame pointer of 'map')?
Comment #2 by k.hara.pg — 2012-07-30T08:56:24Z
(In reply to comment #1)
> Do you mean, that the context pointer would be the frame pointer of the
> function which made the call? (rather than the frame pointer of 'map')?
I mean: with current dmd, Result always requires the frame pointer of map, and we cannot kill it. and if pred is a function that requires a frame pointer (e.g. member function, nested function), Result shall have two frame pointers, but it's disallowed.
This issue is a proposal which provides the way to kill the former (== the frame pointer of map).
Comment #3 by code — 2012-07-30T08:59:58Z
Shouldn't it be possible to automatically use the »outermost« context possible, only creating and allocating new nested ones if they are really required?
Comment #4 by andrei — 2012-07-30T09:18:24Z
I'm a bit confused by the example because it uses the symbol "pred" twice. Kenji, could you please change?
Comment #5 by andrei — 2012-07-30T09:22:57Z
I'd personally prefer more explicit handling by the programmer instead of more powerful built-in frame pointer management. At this point I'm unclear on what exactly that would look like.
Comment #6 by k.hara.pg — 2012-07-30T09:33:41Z
(In reply to comment #5)
> I'd personally prefer more explicit handling by the programmer instead of more
> powerful built-in frame pointer management. At this point I'm unclear on what
> exactly that would look like.
See also issue 5710.
Comment #7 by k.hara.pg — 2012-07-30T10:04:28Z
Module level template struct *is inferred* whether it's really nested or not.
struct Map(alias pred, Range) {
Range input;
this(Range r) { input = r; }
@property empty(){ return input.empty; }
@property front(){ return pred(input.front); }
void popFront() { input.popFront(); }
}
auto map(alias pred, Range)(Range r) { return Map!(pred, Range)(r); }
void main() {
int n = 2;
int addN(int x) { return x + n; }
static int add1(int x) { return x + 1; }
auto r1 = map!addN([1,2,3]);
// typeof(r1) is a nested struct, because pred has a frame pointer(FP).
auto r2 = map!add1([1,2,3]);
// typeof(r2) is not a nested struct, because pred doesn't have a FP.
}
But nested struct (declared in function body) cannot receive such treatment.
auto mapN(alias pred, Range)(Range r) {
struct MapN { ... same as above Map ... }
// MapN have always a FP, then if pred has another one, they conflict.
}
auto mapS(alias pred, Range)(Range r) {
static struct MapS { ... same as above Map ... }
// MapS cannot have any FP, then if pred has a FP, MapS cannot access it.
}
My proposal is:
auto mapTS(alias pred, Range)(Range r) {
static struct MapTS(alias pred) { ... same as above Map ... }
// MapTS can infer its actual nest-ness based on the pred2, as like Map.
// But MapTS cannot access mapTS function's FP, because it's static struct.
}
(In reply to comment #4)
> I'm a bit confused by the example because it uses the symbol "pred" twice.
> Kenji, could you please change?
To ignite such nest-ness inference for MapTS, mapTS should pass the pred to inner struct.
----
But, maybe, this proposal is a little complicated than the rule that you think in your head. We might be able to be simplify the rule.
Comment #8 by code — 2012-07-30T10:15:24Z
(In reply to comment #7)
> But nested struct (declared in function body) cannot receive such treatment.
Why can't it? The nested struct simply gets as many context pointers as it needs, this can be zero if it accesses neither the local or the pred context, one, or two. In the latter case, the context pointer is really a pointer to a struct reps. an array containing the two context pointers, so that it has still the same ABI.
Comment #9 by k.hara.pg — 2012-07-30T10:37:25Z
(In reply to comment #8)
> (In reply to comment #7)
> > But nested struct (declared in function body) cannot receive such treatment.
>
> Why can't it? The nested struct simply gets as many context pointers as it
> needs, this can be zero if it accesses neither the local or the pred context,
> one, or two. In the latter case, the context pointer is really a pointer to a
> struct reps. an array containing the two context pointers, so that it has still
> the same ABI.
Are you talking about issue 5710? This enhancement doesn't cover it (I think it requires ABI level changing, and this doesn't).
---
If you talking about this, the reason is template instantiation mechanism problem. To implement this enhancement, the nested struct should be instantiated depends on the enclosing scope of template declaration. But current dmd doesn't consider it.
Last weekend, I had tried to implement this, but It was not easy.
Comment #10 by clugdbug — 2012-07-30T10:50:21Z
> (In reply to comment #7)
> > But nested struct (declared in function body) cannot receive such treatment.
>
> Why can't it? The nested struct simply gets as many context pointers as it
> needs, this can be zero if it accesses neither the local or the pred context,
> one, or two. In the latter case, the context pointer is really a pointer to a
> struct reps. an array containing the two context pointers, so that it has still
> the same ABI.
Are we certain that you can never get more than two context pointers?
Comment #11 by code — 2012-07-30T11:12:35Z
(In reply to comment #10)
> > (In reply to comment #7)
> > > But nested struct (declared in function body) cannot receive such treatment.
> >
> > Why can't it? The nested struct simply gets as many context pointers as it
> > needs, this can be zero if it accesses neither the local or the pred context,
> > one, or two. In the latter case, the context pointer is really a pointer to a
> > struct reps. an array containing the two context pointers, so that it has still
> > the same ABI.
>
> Are we certain that you can never get more than two context pointers?
I was referring to the specific example mentioned by Kenji. The array could hold arbitrarily many pointers.
Comment #12 by robert.schadek — 2024-12-13T18:00:47Z