-
Notifications
You must be signed in to change notification settings - Fork 17.9k
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: allow callers to override IsTrue #28391
Comments
Please use https://play.golang.org for examples in issue reports when possible. That makes the details much easier for others to investigate. |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
Actually, I think the documentation problem is a separate issue. I'll split it out. |
In what context do you need a For example, I imagine that you could do I realise that using a struct as a boolean inside a template doesn't make much sense, and I would intuitively think that would be an error like it is in plain Go. Either way, I haven't seen a need for that specific use case yet. |
My particular use case is this: Hugo have some template funcs that now typically return a map. The caller would typically then do:
Now, since the But in the error case, since Go templates do not allow So, I would like to do something ala: {{ $result := someFunc }}
{{ if $result }}
{{ else }}
{{ if $result.Error }}
{{ end }}
{{ end }} You may argue that I should create some But I can probably also make the Go's templates are ... very reflective. You have no type switches etc., so to require that the client has a deep understanding of the types it receives just does not work at scale. And what you then end up with is return values of slice, map and pointer types. |
Also, the |
Why not just write a method on the type or a function that returns a boolean? |
Go templates are on some fundamental levels very different from Go code. The template funcs are dynamic from the caller's standpoint. He/she often does not care if it is a struct or a map. And the {{ $result := invokeFunc }}
{{ with $result }}
// do something
{{ end }}
The above is from the GoDoc comment on |
Thanks for the input. I understand that you need to keep backwards compatibility with previously written templates that interact with Hugo, so you can't replace a map with a struct. However, wouldn't you need these templates to be changed to make use of the added error value/string too? It seems to me like existing templates would be outdated one way or another. Adding an So I'm trying to figure out if there's another way to help this use case without complicating |
Sure, but the "another" way is estimated to be a lot less work. Which I like.
How would this complicate And, reading the existing documentation, the current implementation is not correct in the "zero of its type" case (I assume we agree on that a struct also has a zero value):
To each its own. It smells like a bug fix to me :-) |
You mean a I presume that in Hugo's case one would supply a template without ever seeing that option being set, so I'm not sure that it would help avoid confusion. In my previous comment, I meant complexity in terms of a template's behavior being predictable for users.
Yes; that's been separated into #28394. I don't think that matters here; even if we changed the implementation to have structs behave like maps, you'd still have the same problem, I think. I personally haven't made up my mind on this issue. The request seems reasonable, but I'd prefer if there was a solution that didn't involve running arbitrary code to determine truthiness. Let's see if @robpike or @rogpeppe have any thoughts. |
No, I meant
The first part is correct. But I'm confident that If I could adjust the "truth" function, the net amount of confusion among Hugo users would be reduced by >= 40%. And I picked that number out of a hat. The point is that the real cost of explaining this confusing behavior to the users is mainly paid by the Hugo maintainers, not Go maintainers. The tens of thousands of Hugo users do not come to this issue tracker to complain. Consider that before rejecting this issue. |
Given that Setting a global variable is out, as that effects all clients of text/template in the whole program, not all of whom might want that behaviour. A template option could work to enable some predefined behaviour such as recognizing If there was a good use case for adding an arbitrary truthiness function, one could add:
or maybe:
but if not (and I'm not really seeing it), then an option like this might seem better.
If you really wanted an arbitrary truth function later, you could always add
without loss of backward compatibility. |
I'm not trying to reject this issue :) I'm trying to reason about it publicly so others can point out better ideas or whether there's a flaw in my thinking. If anything, I lean in favor of changing the API in some way, because I agree that currently it's somewhat arbitrary and stiff. I agree with Roger that modifying the template package in a global way isn't a good idea. Unless you meant I also think that a In any case, I'll mark this as needing a decision, as I'm not the primary owner of the package. |
It should obviously not be a global thing, so yes.
I'm fine with both suggestions above (but I don't think |
Would |
That was my idea, but note that my example above isn't my only use for this change. And that particular example is a compromise -- I can define my own This (which does not work): {{ $v, $err := invokeFunc }}
{{ if $err }}
... In the above If I define a {{ $v := invokeFunc }}
{{ if $v.Error }}
... But for people who don't care about the error value ( {{ $v := invokeFunc }}
{{ with $v}}
... And since the above is already a very common pattern, I can gradually introduce this "new pattern" without having to add a bunch of |
Thanks for the explanation - then I agree that adding I'd like to hear Rob's thoughts on the revised idea, since he's the main owner of the package. I presume this change could still be done for 1.12, assuming we can reach a consensus in the following week. |
I don't think you need an option, just a new template function iszero. The "option" is just whether you call it or not. I'm not sure what "the revised idea" is, in any case. This is a long confusing discussion. |
Let me try to summarize the discussion above.
If I could get
@robpike suggests that a new
I have purposely made the above a little more clumsy than it could have been to make my point look better. But the |
@robpike So I think you're suggesting that if there is a template function named "iszero" of the right type, it will be called to determine whether a value is true. This might change the behavior of existing templates that already have an "iszero" function. Would that be OK? |
If the iszero function is built in to the template package, any user-added function with the same name would override it. |
@robpike If I read you correctly, you suggest that we instead
Not sure how that is an improvement of any of the two suggestions above, but if that what's needed to solve this issue, so be it. |
A quick note: I didn't really understand the suggested solution, so I found an alternative way to solve this particular issue for me. But I still think this is a good suggestion. |
The
IsTrue
, which is used in templates to determine ifif
andwhen
etc. conditionals should be invoked makes sense in most situations. Some examples:My main challenge with the above is that
Struct values are always true
-- even the zerotime.Time
value above.It would be useful if the above method could check some additional
truther
interface:If the above is considered a breaking change, an alternative suggestion would be to make the
template.IsTrue
function settable.The text was updated successfully, but these errors were encountered: