Trouble exporting function with anonymous struct containing anonymous fields as parameter

139 views
Skip to first unread message

Óscar Carrasco

unread,
Nov 16, 2021, 5:51:39 PM11/16/21
to golang-nuts
Hello, my issue is similar to: 

In this particular case, it is fixed by exporting the fields capitalizing the field name. But, what if the struct fields are also anonymous?

main.go:
----------------------------------------------------
package main

import "a/b"

func f(s struct{ byte }) {}

func main() {
s := struct{ byte }{}
f(s)   // This works
b.F(s) // This gives an argument type error
}
----------------------------------------------------

b/b.go:
----------------------------------------------------
package b

func F(c struct{ byte }) {
}
----------------------------------------------------

By building this code, we get the following compiler error:
`cannot use s (type struct { byte }) as type struct { byte } in argument to b.F`

In my opinion, it should be allowed to export the unnamed (anonymous) types so the struct can be used anywhere else. Opinions on this?

Kevin Chowski

unread,
Nov 16, 2021, 10:25:47 PM11/16/21
to golang-nuts
It's not clear to me what problem you are solving. Can you clarify *why* you want to do this?

For what it's worth, this seems correct to me: a function defined in package X should not be able to access the unexported fields of a struct in package Y. If you embed a 'byte' into a struct, that is an exported field and should not be accessible to other packages.

Kevin Chowski

unread,
Nov 16, 2021, 10:27:05 PM11/16/21
to golang-nuts
Sorry, I included a typo. I have edited my reply below to fix it.

On Tuesday, November 16, 2021 at 8:25:47 PM UTC-7 Kevin Chowski wrote:
It's not clear to me what problem you are solving. Can you clarify *why* you want to do this?

For what it's worth, this seems correct to me: a function defined in package X should not be able to access the unexported fields of a struct in package Y. If you embed a 'byte' into a struct, that is an *un*exported field and should not be accessible to other packages.

Axel Wagner

unread,
Nov 17, 2021, 2:28:44 AM11/17/21
to Óscar Carrasco, golang-nuts
To expand on Kevin's answer:

To call a function, the argument must be assignable to the parameter type of the function.
In this case, none of the types involved is a defined type, channel, interface, pointer…, so the only case left for them to be assignable would be if the types are identical, and:

Two struct types are identical if they have the same sequence of fields, and if corresponding fields have the same names, and identical types, and identical tags. Non-exported field names from different packages are always different.

(emphasis mine)

Therefore, in the case of `b.F(s)` does not work, as the `byte` fields have different names - they might be written out the same, but as they are from different packages, they are considered different names. `f(s)` does work, as in that case the field names are from the same package.

reflect also exposes this semantic. For unexported fields (and only for those) it sets the `PkgPath` as well. So you can think of unexported field names as being implicitly qualified by their package path.

--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/dcd6d246-4091-49da-8631-450829e6de68n%40googlegroups.com.

Brian Candler

unread,
Nov 17, 2021, 3:17:31 AM11/17/21
to golang-nuts
The way to deal with this is to define (and export) a type which contains the hidden fields:

Clearly, the user of this type in another package won't be able to access the hidden fields - so usually you'd also export some sort of constructor function.
Reply all
Reply to author
Forward
0 new messages