Description
This issue is a rework of #30481, which I felt was closed a little prematurely. This is, on one or more levels, a real issue that needs to be addressed. I will try to make this shorter and to the point.
The program below prints:
<nil>: IsTrue: false: Nil == nil: true
*main.Nill: IsTrue: false: Nil == nil: false Failed, got <nil>
Also see https://play.golang.org/p/HzwnX062jjk
The documentation for template.IsTrue states that
IsTrue reports whether the value is 'true', in the sense of not the zero of its type, and whether the value has a meaningful truth value. This is the definition of truth used by if and other such actions.
So, while I understand that Nil != nil
in the second example above, which, I suspect, is part of the reason why the template
package uses reflect
. I would expect that all values that is truthful according to template.IsTrue
is also truthful in if
and with
.
package main
import (
"bytes"
"fmt"
"log"
"text/template"
)
type Niller interface {
Nil() Niller
Foo() string
}
type Nill struct {
nilv Niller
}
func (n Nill) Nil() Niller {
return n.nilv
}
func (n Nill) Foo() string {
return "asdf"
}
func main() {
tmpl, err := template.New("").Parse(`
{{- with .Niller.Nil }}{{ if not $.IsTrue }}Failed, got {{ . }}{{ end }}
{{- else }}{{ if $.IsTrue }}Failed else{{ end -}}
{{ end -}}
`)
if err != nil {
log.Fatal(err)
}
var (
nil1 Niller
nil2 *Nill
)
execute(tmpl, nil1)
execute(tmpl, nil2)
}
func execute(tmpl *template.Template, niller Niller) {
var buff bytes.Buffer
n := &Nill{nilv: niller}
isTrue, ok := template.IsTrue(n.Nil())
if !ok {
log.Fatal("IsTrue failed")
}
data := map[string]interface{}{
"IsTrue": isTrue,
"Niller": n,
}
err := tmpl.Execute(&buff, data)
if err != nil {
log.Fatal(err)
}
fmt.Printf("%T:\t IsTrue: %t: Nil == nil: %t %s\n", niller, isTrue, (n.Nil() == nil), buff.String())
}