-
Notifications
You must be signed in to change notification settings - Fork 111
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
[DISCUSSION] Exposing the underlying struct #100
Comments
Why not -- are you looking for more serializations than the existing MarshalBinary, MarshalText MarshalJSON? |
So, this is an issue for deserializing because we need a concrete struct to deserialize into. However, I'm not sure what the issue is for serialization. Note: there's also the tricky fact that we now have two concrete implementations: |
Yeah, I've encountered this hindrance in the past. I get the impression the goal was to enable diversity of multiaddr implementations, but I can't see a use case for that. |
IMO, we should implement |
Ah, I see what you mean. Treating |
Hm, no, you're right. We could add newtypes but we can't implement it directly (I sometimes blissfully forget about go's type system). |
i think if we keep the interface and just expose the strict as well, it should solve our problem |
@bigs could you explain how this solves the problem? Having to type assert to the concrete type is going to be annoying. |
@Stebalien i misspoke earlier when i said serialization was the issue. it's only deserialization. there's a somewhat prevalent pattern, for example in the datastores, of having something like
where being able to to say var bytes []byte
var addr *multiaddr.Multiaddr
if err := addr.UnmarshalJSON(bytes); err != nil {
panic(err)
} makes it possible for users to seamlessly read in json objects with string representations of multiaddrs. we could keep the signature of |
So, the issue I have with that is that the struct would need to be:
But now, when I want to create this thing, I have to convert from my I wonder if using refmt would help? refmt allows specifying explicit transforms so it may be possible to specify how to decode a multiaddr. |
ah, you know, that's a fair point. i think it's still probably worth it, because it would only be adding functionality, not removing or hindering anything. that said, it would be wonderful to have some multiaddr magics for refmt! could be a convenience package. |
I am going to bump this. I have custom code to wrap multiaddresses into a type that knows how to deserialize itself. Having to do that is worse than anything. Could I convince you to remove the interface(s) altogether and use a concrete struct type instead, since nowhere this is used as an interface with alternate implementations, and right now it is a pain? (This would be backwards compatible as this type would have all the methods from the interface). |
@hsanjuan I'm convinced. Multiaddrs are used everywhere, this indirection has proven useless over time (we have zero alternative implementations), adds a performance cost, and multiaddrs are a data containers per spec, not an abstraction over alternative data structures. The above use case mentioned by @Stebalien -- using the Multiaddr as a canonical interface to things like TCPAddr -- is not feasible in go, because we can't extend types beyond their definition site. We are going to need translation/wrapper types/methods either way. I'm very annoyed because the way it's implemented, we are totally unable to unmarshal multiaddrs, for obvious reasons. In fact, the unit tests blissfully use the private type. This is BOA (broken on arrival), in my opinion: go-multiaddr/multiaddr_test.go Lines 626 to 629 in 5b1de2f
Something basic I'd like to be able to do: ma, err := multiaddr.NewMultiaddr("/ip4/127.0.0.1/tcp/5001")
if err != nil {
panic(err)
}
bytes, err := json.Marshal(ma)
if err != nil {
panic(err)
}
fmt.Println((string)(bytes))
var addr multiaddr.Multiaddr
err = json.Unmarshal(bytes, &addr)
if err != nil {
panic(err)
}
fmt.Println(addr)
|
So, we are now using multiple implementations. Specifically, we have However, we can just export type Bar struct {
Addr ma.Multiaddr
}
func main() {
b := Bar{Addr: new(ma.GenericMultiaddr)}
json.Unmarshal([]byte(`{"Addr": "/ip4/1.2.3.4"}`), &b)
fmt.Println(b)
} But that's still kind of crappy as we need to partially initialize the struct. An alternative is to use refmt which allows specifying per-type decoders. |
As I just ran into this issue, has there been any further development on this? Specifically, I was trying to exchange host addresses in testground between different servers without relying on discovery mechanisms. |
I'll just make a dumb proposal: We could refactor the That's the most straightforward but also least-harmful way I can think of doing it. I will be happy to create a PR. Waiting for comments first, though. |
Hey guys, ran into this error recently too while trying to unmarshall Multiaddrs from json. Ended up having to redefine it as |
In my opinion, hiding the underlying multiaddr struct is a hinderance, particularly when working with serializations in golang (looking at flags and encoding/json). Is there any reason we couldn't simply expose the struct and keep its member hidden? This would enable us to implement interfaces that require zero values.
The text was updated successfully, but these errors were encountered: