Open akclace opened 4 months ago
I think we need to define some semantics and I think there are likely open questions (and in part without obvious answers).
First, obviously, there are one- and two-variable iterators. What should .
be set to in {{ range $x }}
, if $x
is iter.Seq2[A, B]
? For map[K]V
we set it to the values, which would indicate it should be B
, for consistency. On the other hand, there is no a priori guarantee that the second argument of an iter.Seq2
really is necessarily "value-like".
Then we have the range
form {{ range $x, $y := $z }}
, that is, a range
action that initializes one or two variables. Presumably, using two variables with an iter.Seq
will be an error. Should it also be an error to use one variable with an iter.Seq2
(see also #65236)?
Lastly: If calling a function or method in a template (either by using a function name as an action, or using the call
function), the function can optionally return a second argument of type error
: If that error
is not nil
, execution of the template is aborted and the error is returned. This brings up the question of how to handle iter.Seq2[T, error]
.
AIUI it is not entirely clear how error handling with iterators will work, really. For example, if you have an iterator that reads lines from a file, parsing each line into a struct, there are two ways it can fail: 1. a Read
can fail, fatally aborting iteration or 2. the parsing of a single line can fail, allowing to handle the error of that line differently, but continue iteration. Some have suggested using an iter.Seq2[T, error]
for both, in which case a template action ranging over it should probably abort if an error occurs. On the other hand, it might be reasonable to want to still handle that error from the template and continue iteration as well - and only abort on "fatal" errors. I'm not sure how much we want to make a policy choice about that at this point.
An alternative I could imagine is to say that you can range
over an iter.Seq2
in three ways: 1. {{ range $it }}
, which yields the T
and aborts template execution if the second argument is an error, 2. {{ range $x := $it }}
which behaves the same (but sets $x
instead of .
) and 3. {{ range $x, $err := $it }}
, which does not abort on errors, allowing the template to handle it as it pleases. This would effectively put the control over what to do into the hands of the template author.
If we were to go with that suggestion, we would probably want to make {{ range $it }}
/{{ range $x := $it }}
yield the A
s when applying it to an iter.Seq2[A, B]
- inconsistently with maps, but more consistently with iter.Seq2[T, error]
.
At least those are my thoughts. There are probably other ways to define these semantics.
Presumably, using two variables with an
iter.Seq2
will be an error.
I assume this is a typo for iter.Seq
.
@earthboundkid Correct, edited, thanks.
Regarding the semantics, it seems like we should require that if the iterator yields 2 values, then you have to use the {{range $x, $y := $f}} form.
This proposal has been added to the active column of the proposals project and will now be reviewed at the weekly proposal review meetings. — rsc for the proposal review group
It would be consistent to allow ranging over int as well.
This seems fine but we should wait for #66056 to help with the implementation.
Based on the discussion above, this proposal seems like a likely accept. — rsc for the proposal review group
The proposal is to allow range over func and int the same as in Go.
No change in consensus, so accepted. 🎉 This issue now tracks the work of implementing the proposal. — rsc for the proposal review group
The proposal is to allow range over func and int the same as in Go.
Change https://go.dev/cl/596956 mentions this issue: text/template: support range-over-func
Proposal Details
The Rangefunc change is adding support for range on custom functions.
The text/html template std library has a range operator which is documented as
The template library should support range over a function. The use case is wanting to return a Rangefunc on top of a sql rows iterator which can be passed to the template for text generation.
This was the discussion in the group https://groups.google.com/g/golang-nuts/c/_lykyoQHmGc