4 ms·
> Go's confusion between "type aliases" and "newtypes". The only way to make a newtype in go is to make a separate package with an opaque type and use interface
by foldr 5y ago
> Go's confusion between "type aliases" and "newtypes". The only way to make a newtype in go is to make a separate package with an opaque type and use interfaces for indirection, which is costly and awkward.
It's very unclear what this is supposed to mean. 'type Foo int' in Go creates a new 'Foo' type that can't be used as an int without casting (a̶l̶t̶h̶o̶u̶g̶h̶ ̶y̶o̶u̶ ̶c̶a̶n̶ ̶a̶s̶s̶i̶g̶n̶ ̶a̶n̶ ̶i̶n̶t̶ ̶t̶o̶ ̶i̶t̶). If you don't want to allow that, you can just wrap it in a single member struct.
- paskozdilar 5y ago> 'type Foo int' in Go creates a new 'Foo' type that can't be used as an int without casting (although you can assign an int to it). You can't, in fact: type Foo int func main() { var foo Foo = 1 var bar int = 2 foo = bar // cannot use bar (variable of type int) as Foo value in assignment } The reason you can do things like: var foo Foo = 1 is that because numeric literals in Go are not ints, they are untyped [0]. [0] https://go.dev/blog/constants https://go.dev/blog/constants
- foldr 5y agoAh yes, good point. Thanks for the correction.
- smasher164 5y agoYeah, his complaint about newtypes is just incorrect.
- fasterthanlime 5y agoI moved some words around to make the nit less confused - thanks for the feedback!
- foldr 5y agoStill not seeing it. You don't have to use interfaces to make an opaque type. A package boundary is sufficient. Not sure why you would want a fully opaque type internally to a package anyway. A regular `type Foo Bar` declaration is sufficient to give you a `Foo` that can't be accidentally interchanged with a `Bar`.
- howinteresting 5y agoYou generally want newtypes as proofs that a value has gone through some validation.
- foldr 5y agoAnd what prevents you using them this way in Go? Just make a package and export a constructor function that does the validation.
- Tomis02 5y agoI think that was the author's point. You _can_ use them this way but it's a hassle and most people don't do it. The language itself doesn't protect you against zero-initialisation errors, even though it could.
- deleted 5y ago[deleted]
- fasterthanlime 5y agoThat's not the only/main reason to want a newtype though - it's also about restricting what the value can be, see something like NonZeroU64: https://doc.rust-lang.org/stable/std/num/struct.NonZeroU64.html https://doc.rust-lang.org/stable/std/num/struct.NonZeroU64.h... numeric literals (mentioned by paskozdilar in a parent comment) being untyped is another footgun I hadn't even thought of including - it makes it impossible to achieve in TypeScript/Java-level enums.
- foldr 5y agoYou can define NonZeroU64 in Go exactly the same way it's defined in Rust – as a struct with a private field. No interfaces required. But I was wondering why you would want an opaque type internally to a package. Presumably not to ensure that the value has passed some validation, since in that case you would want to encapsulate that validation logic in its own package. It's not like Go imposes a tax on packages. Packages are the unit of encapsulation in Go, just as modules are the unit of encapsulation in Rust.