Skip to content

proposal: reflect: add method (Value) IsEmpty() #59451

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

Closed
cuishuang opened this issue Apr 5, 2023 · 11 comments
Closed

proposal: reflect: add method (Value) IsEmpty() #59451

cuishuang opened this issue Apr 5, 2023 · 11 comments

Comments

@cuishuang
Copy link
Contributor

cuishuang commented Apr 5, 2023

Recently, I am working on a project that frequently uses reflection, and there are many scenarios where I need to determine whether the reflect.Value is empty (different from the existing IsZero).

I searched the source code and found similar private methods with redundancy scattered across two packages:

https://github.com/golang/go/blob/master/src/encoding/json/encode.go#L303

https://github.com/golang/go/blob/master/src/encoding/xml/marshal.go#L1118

func isEmptyValue(v reflect.Value) bool {
	switch v.Kind() {
	case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
		return v.Len() == 0
	case reflect.Bool:
		return v.Bool() == false
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		return v.Int() == 0
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
		return v.Uint() == 0
	case reflect.Float32, reflect.Float64:
		return v.Float() == 0
	case reflect.Interface, reflect.Pointer:
		return v.IsNil()
	}
	return false
}

I would like to discuss whether it is possible to add a new method IsEmpty to the reflect package, which eliminates the need for duplicate definitions in individual projects and simplifies existing source code.

Just like this https://go-review.googlesource.com/c/go/+/482415

@gopherbot gopherbot added this to the Proposal milestone Apr 5, 2023
@gopherbot
Copy link
Contributor

Change https://go.dev/cl/482415 mentions this issue: all: use IsEmpty to simplify code

@mvdan
Copy link
Member

mvdan commented Apr 5, 2023

cc @dsnet

@dsnet
Copy link
Member

dsnet commented Apr 5, 2023

I'm not sure these are great examples of why this should be added in reflect:

  • Go reflection is intended to be a programatic way to do what you can do in the Go language itself. TheIsZero method exists because the zero value is part of the Go specification. On the other hand, this particular definition of "empty" is not found in the Go specification.
  • The definition of IsEmpty is fairly arbitrary and there's discussion of changing the semantic for a hypothetical v2 "encoding/json". For example, an empty array is not a particularly useful attribute, and the lack of some definition of an "empty" struct has been problematic.
  • Two internal usages in the standard library is not really justification to add it as an exported method in "reflect". At best, it might suggest a shared internal package, but I don't think the complexity of this function justifies even that.

@earthboundkid
Copy link
Contributor

@cuishuang
Copy link
Contributor Author

I'm not sure these are great examples of why this should be added in reflect:

  • Go reflection is intended to be a programatic way to do what you can do in the Go language itself. TheIsZero method exists because the zero value is part of the Go specification. On the other hand, this particular definition of "empty" is not found in the Go specification.
  • The definition of IsEmpty is fairly arbitrary and there's discussion of changing the semantic for a hypothetical v2 "encoding/json". For example, an empty array is not a particularly useful attribute, and the lack of some definition of an "empty" struct has been problematic.
  • Two internal usages in the standard library is not really justification to add it as an exported method in "reflect". At best, it might suggest a shared internal package, but I don't think the complexity of this function justifies even that.

Thank you.

However, it is strange that there are dozens of lines of identical code in the two packages. Do we currently need to put this into an internal public package?

@ianlancetaylor ianlancetaylor moved this to Incoming in Proposals Apr 5, 2023
@ianlancetaylor
Copy link
Member

What is the precise definition of IsEmpty? How precisely does it differ from IsZero? We need to be able to write that down without just showing code. Thanks.

@cuishuang
Copy link
Contributor Author

What is the precise definition of IsEmpty? How precisely does it differ from IsZero? We need to be able to write that down without just showing code. Thanks.

Thanks.

IsEmpty reports whether v is an empty value for its type. When v is of type int/uint/float/bool/string, its processing logic is completely consistent with IsZero. But when v is array/slice/map, if the length is 0, it will return true, without calling IsNil

@earthboundkid
Copy link
Contributor

earthboundkid commented Apr 10, 2023

Channels have a length. Is empty the same as nil or same as the length? I think nil, but maybe it’s controversial.

@ianlancetaylor
Copy link
Member

IsEmpty reports whether v is an empty value for its type.

Thanks, and I know that I'm being pedantic, but that can't be the right definition. The implementation of IsEmpty that I see above will always return true for the type [0]byte and will never return true for [1]byte. And as far as I can see that implementation will always return false for a struct type, even for a struct type with no fields. So at least for an array or struct type the implementation of IsEmpty above doesn't have anything to do with the value, only with the type.

These details matter if we're going to add a new exported method to the standard library. It has to have a clear definition and clear purpose apart from any use in the json or xml packages.

Looking further at the encoding/json package, I see that the definition there, for the "omitempty" option, is "false, 0, a nil pointer, a nil interface value, and any empty array, slice, map, or string." I don't think that's useful enough to add to the reflect package.

@cuishuang
Copy link
Contributor Author

IsEmpty reports whether v is an empty value for its type.

Thanks, and I know that I'm being pedantic, but that can't be the right definition. The implementation of IsEmpty that I see above will always return true for the type [0]byte and will never return true for [1]byte. And as far as I can see that implementation will always return false for a struct type, even for a struct type with no fields. So at least for an array or struct type the implementation of IsEmpty above doesn't have anything to do with the value, only with the type.

These details matter if we're going to add a new exported method to the standard library. It has to have a clear definition and clear purpose apart from any use in the json or xml packages.

Looking further at the encoding/json package, I see that the definition there, for the "omitempty" option, is "false, 0, a nil pointer, a nil interface value, and any empty array, slice, map, or string." I don't think that's useful enough to add to the reflect package.

I searched other files of the standard library, and there is no other similar use except these two places. It is indeed a bit of a luxury to add a new method in the standard library, because the frequency of use is not enough. Thank you for your patience and reply.

@cuishuang
Copy link
Contributor Author

Closing this proposal: Doesn't seem necessary.

Thanks to everyone who participated in the discussion.

@golang golang locked and limited conversation to collaborators Apr 10, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

6 participants