-
Notifications
You must be signed in to change notification settings - Fork 18k
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
reflect: assignment compatibility doesn't include nil #6231
Labels
Comments
The basic problem is that the zero value is used in two different ways - as a genuinely invalid value (as returned by Indirect, Elem, FieldByName, FieldByNameFunc, MapIndex, MethodByName and TryRecv), and as the result of reflect.ValueOf(nil). I would be happy if reflect.ValueOf(nil).IsValid() was true, but that's not a change we can make. I don't think it's too much of a problem that the zero value returned by the above calls becomes assignment-compatible with nilable values (and it's still unambiguous in all those cases, as a valid value returned by those methods will always have a valid type, AFAICS). However SetMapIndex is problematic, as it uses IsValid to determine whether it should delete the key from the map, whereas my proposal would suggest that it should assign a nil value to the map. I think that means that it's not viable, sadly. I would still very much like to see some kind of better way of working around this issue, however. I have so far encountered the issue in at least separate domains so far (assignment, channel sends and function calls) and, experimentally, people do not see any potential problem with the naive code even when specifically told that there's a problem there. Perhaps a method like this might help, as an adjunct to Convert: // AsType returns the value v with the given type t. // As a special case, if v is the zero Value and t // is a type that may have a nil value, AsType returns // the nil value of that type. // If v is not assignable to type t, AsType panics. func (v Value) AsType(t Type) Value Alternatively: // ValueOfType is the same as ValueOf except that the // returned value will always have type t. If i is nil // and values of type t may be nil, the returned value // will be reflect.Zero(t); otherwise if i is not assignable // to type t, ValueOfType will panic. // // This can be useful when converting an externally supplied value // that will be assigned to some known type. func ValidValueOf(i interface{}, t Type) reflect.Value It's would still be awkward to use (particularly when using Value.Call) but still better than the status quo, I think. |
It is a mistake to try to overload the zero Value. The problem here is a bad interaction between ValueOf and interfaces. Because ValueOf takes an interface{}, the static type of the argument is lost and cannot be recovered. You are arguing that the result in this case should have type interface{}, but what if the argument was a nil io.Reader? Yes, the API has a flaw. But it's pretty fundamental to the use of the interface{} as an argument. It's better to leave the flaw than make things worse by adding patches. In your case, it is easy to check for src == nil in your wrapper. http://play.golang.org/p/FiPiyKtPmi Status changed to WorkingAsIntended. |
"In your case, it is easy to check for src == nil in your wrapper. http://play.golang.org/p/FiPiyKtPmi" That's tempting, but doesn't quite get the effect I intended - you can then pass nil for non-nilable types. http://play.golang.org/p/kNOIMy7aqB I'd like a straightforward way to do it properly. |
This issue was closed.
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
The text was updated successfully, but these errors were encountered: