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

proposal: text/template: range over func and int #66107

Open
akclace opened this issue Mar 4, 2024 · 7 comments
Open

proposal: text/template: range over func and int #66107

akclace opened this issue Mar 4, 2024 · 7 comments
Labels
Milestone

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.

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
Status: Active
Development

No branches or pull requests

6 participants