Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

text/template: range over func and int #66107

Closed
akclace opened this issue Mar 4, 2024 · 11 comments
Closed

text/template: range over func and int #66107

akclace opened this issue Mar 4, 2024 · 11 comments

Comments

@akclace
Copy link

akclace commented Mar 4, 2024

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

{{range pipeline}} T1 {{end}}
    The value of the pipeline must be an array, slice, map, or channel

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

@gopherbot gopherbot added this to the Proposal milestone Mar 4, 2024
@seankhliao seankhliao changed the title proposal: text template range over Rangefunc proposal: text/template: range over Rangefunc Mar 4, 2024
@Merovius
Copy link
Contributor

Merovius commented Mar 5, 2024

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 As 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.

@earthboundkid

This comment was marked as resolved.

@Merovius

This comment was marked as outdated.

@ianlancetaylor ianlancetaylor moved this to Incoming in Proposals Mar 6, 2024
@rsc
Copy link
Contributor

rsc commented Mar 6, 2024

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.

@rsc rsc moved this from Incoming to Active in Proposals Mar 8, 2024
@rsc
Copy link
Contributor

rsc commented Mar 8, 2024

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

@leb-kuchen
Copy link

It would be consistent to allow ranging over int as well.

@rsc rsc changed the title proposal: text/template: range over Rangefunc proposal: text/template: range over func and int Mar 13, 2024
@rsc
Copy link
Contributor

rsc commented Apr 16, 2024

This seems fine but we should wait for #66056 to help with the implementation.

@rsc rsc moved this from Active to Likely Accept in Proposals May 8, 2024
@rsc
Copy link
Contributor

rsc commented May 8, 2024

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.

@rsc
Copy link
Contributor

rsc commented May 15, 2024

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.

@rsc rsc moved this from Likely Accept to Accepted in Proposals May 15, 2024
@rsc rsc changed the title proposal: text/template: range over func and int text/template: range over func and int May 15, 2024
@rsc rsc modified the milestones: Proposal, Backlog May 15, 2024
qiulaidongfeng added a commit to qiulaidongfeng/go that referenced this issue Jul 7, 2024
Fixes golang#66107

Change-Id: If3e503efca200aa86463c9d27d06986b03c0d638
qiulaidongfeng added a commit to qiulaidongfeng/go that referenced this issue Jul 7, 2024
Fixes golang#66107

Change-Id: If3e503efca200aa86463c9d27d06986b03c0d638
@gopherbot
Copy link
Contributor

Change https://go.dev/cl/596956 mentions this issue: text/template: support range-over-func

qiulaidongfeng added a commit to qiulaidongfeng/go that referenced this issue Sep 8, 2024
Fixes golang#66107

Change-Id: If3e503efca200aa86463c9d27d06986b03c0d638
qiulaidongfeng added a commit to qiulaidongfeng/go that referenced this issue Sep 17, 2024
Fixes golang#66107

Change-Id: I2fcd04bebe80346dbd244ab7ea09cbe6010b9d8e
GitHub-Last-Rev: da1a7ac
GitHub-Pull-Request: golang#68329
qiulaidongfeng added a commit to qiulaidongfeng/go that referenced this issue Sep 17, 2024
For golang#66107

Change-Id: I19b466e3fb17557cf4f198b7fd8c13e774d854b1
gopherbot pushed a commit that referenced this issue Sep 23, 2024
For #66107

Change-Id: I2fcd04bebe80346dbd244ab7ea09cbe6010b9d8e
GitHub-Last-Rev: 5ebf615
GitHub-Pull-Request: #68329
Reviewed-on: https://go-review.googlesource.com/c/go/+/596956
LUCI-TryBot-Result: Go LUCI <[email protected]>
Reviewed-by: Carlos Amedee <[email protected]>
Reviewed-by: Ian Lance Taylor <[email protected]>
Auto-Submit: Ian Lance Taylor <[email protected]>
@gopherbot
Copy link
Contributor

Change https://go.dev/cl/615095 mentions this issue: text/template: support range-over-int

qiulaidongfeng added a commit to qiulaidongfeng/go that referenced this issue Sep 23, 2024
Fixes golang#66107

Change-Id: I19b466e3fb17557cf4f198b7fd8c13e774d854b1
qiulaidongfeng added a commit to qiulaidongfeng/go that referenced this issue Sep 25, 2024
Fixes golang#66107

Change-Id: I19b466e3fb17557cf4f198b7fd8c13e774d854b1
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: Accepted
Development

No branches or pull requests

6 participants