Un pointeur nil rangé dans une interface donne une interface qui n'est pas nil.A nil pointer stored in an interface yields an interface that is not nil.
Au numéro précédent, on a vu qu'une valeur d'interface est une paire (type, valeur). C'était une jolie image ; c'est aussi un piège. Car cette paire change le sens de nil. Un pointeur peut être nil — c'est une valeur parfaitement ordinaire. Mais dès qu'on range ce pointeur nil dans une interface, la case « type » se remplit avec son type concret, et l'interface, elle, cesse d'être vide. La comparaison i == nil devient fausse alors même que ce que l'interface contient est nil. C'est le bug le plus déroutant de Go, parce qu'il fait mentir nil — et nil, on lui fait confiance partout.Last issue we saw that an interface value is a (type, value) pair. It was a tidy image; it's also a trap. Because that pair changes the meaning of nil. A pointer can be nil — a perfectly ordinary value. But the moment you store that nil pointer in an interface, the 'type' slot fills with its concrete type, and the interface stops being empty. The comparison i == nil becomes false even though what the interface holds is nil. It's Go's most baffling bug, because it makes nil lie — and nil is something we trust everywhere.
func find() *Node { return nil } // renvoie un *Node bel et bien nil var i any = find() // on le range dans une interface fmt.Println(i == nil) // false ← surprise // le *Node EST nil. L'interface qui le transporte, elle, ne l'est pas.
// une valeur d'interface = DEUX cases : (type, valeur) // var i any → (nil, nil) → i == nil ✓ vrai // var p *Node = nil // i = p → (*Node, nil) → i == nil ✗ faux // nil ne compare vrai que si les DEUX cases sont vides à la fois.
À gauche, l'interface vraiment vide : les deux cases à nil, donc == nil vrai. À droite, la même valeur nulle, mais la case « type » porte *Node — l'interface n'est plus vide. Une interface est nil quand son type l'est, pas quand sa valeur l'est.On the left, the truly empty interface: both slots nil, so == nil is true. On the right, the same null value, but the 'type' slot carries *Node — the interface is no longer empty. An interface is nil when its type is, not when its value is.
« nil dans une interface ne teste pas la valeur, il teste le type. » Tout le numéro découle de là : pourquoi if err != nil peut trahir, comment l'éviter à la source, et pourquoi le problème dépasse de loin les erreurs. La règle pratique tient en une ligne — ne range jamais un pointeur typé nil dans une interface en espérant qu'elle reste nil."nil in an interface doesn't test the value, it tests the type." The whole issue follows: why if err != nil can betray you, how to avoid it at the source, and why the problem reaches far beyond errors. The practical rule fits on one line — never store a typed nil pointer in an interface and expect it to stay nil.
Parce que l'interface doit savoir QUEL type elle transporte pour appeler la bonne méthode — c'est la satisfaction implicite du numéro précédent qui l'exige. La case « type » n'est pas un caprice : c'est elle qui permet à un même io.Writer d'aiguiller vers Write d'un fichier ou d'un buffer. Le prix de cette souplesse, c'est qu'un type non vide suffit à rendre l'interface non vide — même si la valeur, derrière, est absente. Le typed nil n'est pas un bug du langage : c'est la rançon d'une représentation qui doit retenir le type.Because the interface must know WHICH type it carries to call the right method — the implicit satisfaction of last issue demands it. The 'type' slot isn't a whim: it's what lets one io.Writer dispatch to a file's Write or a buffer's. The price of that flexibility is that a non-empty type alone makes the interface non-empty — even if the value behind it is absent. The typed nil isn't a language bug: it's the ransom of a representation that must remember the type.