Skip to content

Commit a2eff80

Browse files
authored
[spec] Improve opApply docs (#3699)
Show grammar for signature. Don't require `ref` delegate parameter. Explain non-ref ForeachType can match a ref OpApplyParameter. Fixes Issue 24176 - Parameters of opApply delegate don't have to be `ref`.
1 parent b04ba82 commit a2eff80

File tree

1 file changed

+43
-15
lines changed

1 file changed

+43
-15
lines changed

spec/statement.dd

Lines changed: 43 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -671,35 +671,62 @@ foreach (string s, double d; aa)
671671
array are iterated over is unspecified for $(D foreach).
672672
This is why $(D foreach_reverse) for associative arrays is illegal.)
673673

674-
$(H3 $(LNAME2 foreach_over_struct_and_classes, Foreach over Structs and Classes with opApply))
674+
$(H3 $(LNAME2 foreach_over_struct_and_classes, Foreach over Structs and Classes with `opApply`))
675675

676676
$(P If the aggregate expression is a struct or class object,
677677
the $(D foreach) is defined by the
678678
special $(LEGACY_LNAME2 opApply, op-apply, $(D opApply)) member function, and the
679679
`foreach_reverse` behavior is defined by the special
680680
$(LEGACY_LNAME2 opApplyReverse, op-apply-reverse, $(D opApplyReverse)) member function.
681-
These functions have the signatures:
681+
These functions must each have the signature below:
682682
)
683683

684-
--------------
685-
int opApply(scope int delegate(ref Type [, ...]) dg);
684+
$(GRAMMAR
685+
$(GNAME OpApplyDeclaration):
686+
`int opApply` `(` `scope` `int delegate` `(` $(I OpApplyParameters) `)` `dg` `)` `;`
686687

687-
int opApplyReverse(scope int delegate(ref Type [, ...]) dg);
688-
--------------
688+
$(GNAME OpApplyParameters):
689+
*OpApplyParameter*
690+
*OpApplyParameter*, *OpApplyParameters*
691+
692+
$(GNAME OpApplyParameter):
693+
$(GLINK ForeachTypeAttributes)$(OPT) $(GLINK2 type, BasicType) $(GLINK2 declaration, Declarator)
694+
)
689695

690-
$(P where $(I Type) determines the type of the first $(GLINK ForeachType)
691-
declared. Multiple $(I ForeachType)s are supported.
692-
Each one must match a parameter of the delegate *dg*,
696+
$(P where each $(I OpApplyParameter) of `dg` must match a $(GLINK ForeachType)
697+
in a *ForeachStatement*,
693698
otherwise the *ForeachStatement* will cause an error.)
694699

700+
$(P Any *ForeachTypeAttribute* cannot be `enum`.)
701+
702+
$(PANEL
703+
To support a `ref` iteration variable, the delegate must take a `ref` parameter:
704+
705+
$(SPEC_RUNNABLE_EXAMPLE_COMPILE
706+
---
707+
struct S
708+
{
709+
int opApply(scope int delegate(ref uint n) dg);
710+
}
711+
void f(S s)
712+
{
713+
foreach (ref uint i; s)
714+
i++;
715+
}
716+
---
717+
)
718+
Above, `opApply` is still matched when `i` is not `ref`, so by using
719+
a `ref` delegate parameter both forms are supported.
720+
)
721+
695722
$(P There can be multiple $(D opApply) and $(D opApplyReverse) functions -
696723
one is selected
697-
by matching each parameter type of *dg* to the type of each $(I ForeachType)
724+
by matching each parameter of `dg` to each $(I ForeachType)
698725
declared in the $(I ForeachStatement).)
699726

700727
$(P The body of the apply
701728
function iterates over the elements it aggregates, passing each one
702-
in successive calls to the $(I dg) delegate. The delegate return value
729+
in successive calls to the `dg` delegate. The delegate return value
703730
determines whether to interrupt iteration:)
704731

705732
$(UL
@@ -751,13 +778,14 @@ $(CONSOLE
751778
73
752779
82
753780
)
754-
$(P The `scope` storage class on the $(I dg) parameter means that the delegate does
755-
not escape the scope of the $(D opApply) function (an example would be assigning $(I dg) to a
756-
global variable). If it cannot be statically guaranteed that $(I dg) does not escape, a closure may
781+
$(PANEL
782+
The `scope` storage class on the $(D dg) parameter means that the delegate does
783+
not escape the scope of the $(D opApply) function (an example would be assigning $(D dg) to a
784+
global variable). If it cannot be statically guaranteed that $(D dg) does not escape, a closure may
757785
be allocated for it on the heap instead of the stack.
758-
)
759786

760787
$(BEST_PRACTICE Annotate delegate parameters to `opApply` functions with `scope` when possible.)
788+
)
761789

762790
$(P $(B Important:) If $(D opApply) catches any exceptions, ensure that those
763791
exceptions did not originate from the delegate passed to $(D opApply). The user would expect

0 commit comments

Comments
 (0)