[HN Gopher] Go Replaces Interface{} with 'Any' ___________________________________________________________________ Go Replaces Interface{} with 'Any' Author : brosciencecode Score : 305 points Date : 2021-12-14 20:24 UTC (2 hours ago) (HTM) web link (github.com) (TXT) w3m dump (github.com) | [deleted] | rackjack wrote: | I'd really like it if Github handled massive commits like this | one better. The way they present it is not very pleasant to | navigate. | moth-fuzz wrote: | I'm not sure I like this change. I liked interface{} since it | just works out naturally from Go's relatively simple type system, | and anyone could come to the conclusion without actually being | told "use interface{} to represent any possible value" just by | having an understanding of that type system. Adding what is | simply a type alias, multiple words for the same underlying | concept, to me just feels like jargon. I admire Go for its | simplicity and clarity and this change gives me anxiety that that | will be obfuscated. | takeda wrote: | Isn't Any essentially: | | type Any interface{} | | ? | throwaway894345 wrote: | I'm pretty sure it's an alias, so: `type any = interface{}`. | | `type any interface{}` would declare a new type, while an | alias is exactly another name for the same type. | [deleted] | erdaniels wrote: | It's a type alias so it's type any = | interface{} | | That means they're interchangeable compared to defining a new | type. | Laremere wrote: | Close, it's: type Any = interface{} | | That is, it's an alias and casting is not necessary. | eadmund wrote: | I agree with you right now, but I wonder if I will change my | mind after having had some experience using the new generics. | Maybe it will feel more natural then? | xh-dude wrote: | I don't think the concern is unreasonable at all but 'any' | feels pretty solid as far as I've had the chance to poke | around. There's some tensions where I think 'any' is arguably | much simpler: | | The baseline is that constraints aren't best expressed as | interface literals in situ. Unlike exceptional use of | 'interface{}', 'any' will be a more naturally invoked | constraint. | | Also, some of the uses of constraints rely on a unification | involving an 'any' term that cancels out. Here, the use of | 'interface{}' is not incorrect but maybe indirect. | arcanon wrote: | Ball is in your court now typescript-on-the-serverside ppl! | tills13 wrote: | I didn't realize there was a "war" going on between the two | groups. | | If there is, I imagine it's not among the type of people who | you'd want leading technical decisions at your company. | friedman23 wrote: | There isn't. What I have noticed in the go community is a | rabid fandom and belief that golang is the pinnacle of | language design when in reality go is a language for people | that think memorizing a few syntactical rules is too | difficult. People used to rabidly defend the lack of generics | for example and look at where we are now. | | And before people identify me as a TS fanboy, I'm not, I'm a | go hater. | jamespwilliams wrote: | I'm not a typescript person, but to be fair to typescript, its | type system is still much more expressive than Go's, even with | the generics addition | [deleted] | woah wrote: | Typescript is stricter and safer while also being less | obtrusive than Go | travisd wrote: | This isn't super clearcut. Typescript has lots of footguns | and famously says that soundness is _not_ one of their | driving factors. There are lots of ways to devolve to | accidental implicit any 's (even with the no implicit any | strict rule turned on). | | Of course, Go makes zero attempt to enforce nullability | (nilability?) in its type system... so... win some, lose | some I guess. | Thaxll wrote: | Any language based on JS can't be safer than Go. The end | result of TS is JS which is a dynamic language. | jwandborg wrote: | The usual end result of Go is machine code, machine code | is not safe to the degree you would consider Go to be | safe. | friedman23 wrote: | Ok, so if Go compiled to JS it would be a dynamic | language? | | https://github.com/gopherjs/gopherjs | fwip wrote: | That's absurd. If TS can't be secure because it compiles | to an unsafe language (JS), Go can't be secure because it | compiles to unsafe assembly. | carlhjerpe wrote: | I don't see how they're competing, TypeScript can still share | code between client and serverside, go "can't". They're not | exclusive to each other, routing "form submissions" though a ts | verification layer and then down to Go makes sense to me if you | need the Go performance but want to share things client and | server side. | | Also, application servers are cheap, persistent, fast and | durable storage isn't, these won't be written in TS. | | TL;DR: different problem domains, not important | AtNightWeCode wrote: | Like it! Now, can they continue to add more "useless" | improvements like while-loops and so on. | karmanyaahm wrote: | https://go.dev/tour/flowcontrol/3 | | for sum < 1000 { sum += sum } | jjice wrote: | Doesn't 'for' work as 'while' if you only give it a condition | in go? I haven't written much, so correct me if I'm wrong. | AtNightWeCode wrote: | Does not Interface{} work as well as Any? I mean, most | languages have while-statements cause it is more clear what | the intention is. | jamespwilliams wrote: | Loading this commit in safari almost killed my phone | jeffbee wrote: | The Gerrit view of the same commit transfers far less data than | the GitHub view. https://go- | review.googlesource.com/c/go/+/368254 | saagarjha wrote: | Loaded just fine on my iPhone SE. I hope you're not using | anything older than that... | hu3 wrote: | Works fine for Firefox on a Pixel 6. Took a couple of seconds | to load then smooth (ginormous) scrolling was available. | | Same for an old Android phone with outdated Snapdragon 660 I | use to test app performance bottlenecks. Except this one took 4 | secs to load. | mseepgood wrote: | It's a type alias, introduced for generics. By the way, Go 1.18 | Beta 1 is released (with generics): | https://groups.google.com/g/golang-announce/c/eAjK4Oezs_A | exdsq wrote: | How is generics not a big enough change to warrant 2.0? | | Edit: I'm impressed generics aren't a breaking change! I | thought this changed Interface{} to Any as a breaking change | preseinger wrote: | It's not a breaking change. | mseepgood wrote: | They are backwards compatible and don't break people's code, | so it's 1.x. | philwelch wrote: | In semantic versioning, going from 1.X to 2.X is only | indicated when there are incompatible API changes. Adding | generics doesn't break compatibility with preexisting Go | code, so it's unnecessary to increment the major version. | keithnz wrote: | Sure, but semantic versioning really is the wrong kind of | versioning to use for a language. The major version should | represent major language changes, not whether its a | breaking change or not, semantic versioning isn't somehow | magically a "good" way to version. It's useful for | libraries / dependencies where you are dealing with many | different libraries and just want to know you can upgrade | without having to deal with breaking changes. For a | language? Silliness. Your version is not really telling you | the main things you care about. | | It's much much more useful to the users to say, 2.0 | introduced generics, it's distinct. If it's like other | languages, generics changes the code people generate a lot, | libraries start looking significantly different. It's very | distinct, and if that is simply in version 1.18.0 or | whatever, that is super bad usability from a language | perspective. | robto wrote: | In Java people regularly refer to a particular JDK | version as a Java 17 or Java 11, even though they | actually refer to versions 1.17 and 1.11, | respectively[0]. In Clojure land they just say 1.x, even | when large new features are added. | | I like this because it emphasizes the community's | commitment backwards compatibility, which I greatly | value. I've spent a good deal of time writing Javascript, | where library developers seem to have very little respect | for their users and constantly break backwards | compatibility. In ecosystems like that, upgrading fills | me with dread. When I see a library on version 4, I have | learned to keep looking - if they weren't thoughtful | enough about their API design for the first 3 major | releases, I shouldn't expect it to be much better going | forwards. | | For an application, I'm pretty open to version numbers | signifying big features - Firefox and Chrome do this, and | it's helpful with marketing. But for a programming | language? A programming language is a tool, and when | upgrading you need to carefully read the changelog | anyways. A programming language is no different from a | library (in Clojure it literally is a library), and | backwards compatibility is /literally/ the main thing I | care about. Is my tool going to intrude on /my/ schedule, | and force me to make changes /it/ wants instead of being | able to spend my time making changes /I/ care about? I | want to know that. | | [0]This is apparently an awful example as I've just | learned that Java is actually doing the major version | only thing. It still sort of works because the only | reason they can do that is because they Will Not Break | Compatiblity. | linkdd wrote: | > In Java people regularly refer to a particular JDK | version as a Java 17 or Java 11, even though they | actually refer to versions 1.17 and 1.8, respectively. | | 17 -> 1.17, 11 -> 1.8, this is bothering me way to much | for no good reason. | danudey wrote: | Clarification: | | * Java 8 is Java 1.8.0 | | * Java 11 is Java 11.0.11 (at the moment) | | * Java 17 is Java 17.0.1 (at the moment) | | SunOS/Solaris is what I use when I want to get nerd-rage | mad about minutae: https://en.wikipedia.org/wiki/Oracle_S | olaris#Version_history | post-it wrote: | I don't think 11 ever referred to 1.8 generally, but for | the longest time the `openjdk-11-*` packages in one of | the Ubuntu LTSes (18.04?) actually installed Java 8 for | some reason. | cortesoft wrote: | Wait, why wouldn't it matter for a language? I want to | know if I can compile my existing project with the new | version... isn't that an important thing to know? | 13415 wrote: | It makes no sense to replace a meaningful and helpful | criterion - whether it breaks code or not - by some | purely subjective assessment of what's a "major change." | That just leads to usual version creep, from "Go 2.2" to | "Go 3.0", to "Go 4.0", to (inevitable) "Go 10", "Go 11", | "Go 11 Pro", "Go 11 Ultimate Edition",... | pawelmurias wrote: | > Can upgrade without having to deal with breaking | changes | | This is actually very important. If something is a major | change or not is pretty subjective. | lanstin wrote: | Not really from my perspective. I want know if there is | any reason to not upgrade due to my existing code base | breaking. Extra new features I could use are not such a | reason. New reserved words are such a reason. If someone | is using a new feature, I can just say "make sure you | have the newest version, also here's my reason for | keeping close to the edge of current versions, so that | you amortize the labor of keeping up to date rather than | pinning and then having some big migration project in 5 | years." | WastingMyTime89 wrote: | > The major version should represent major language | changes, not whether its a breaking change or not | | Why? | | Old code still work and unless you are purposefully | maintaining an old system you are expected to use the | last version anyway. What does it actually change that | generics were introduced in version 1.18 rather than 2.0? | From now on, Go has generics. As there is no breaking | change, it's not like you had to keep using the previous | version to opt out. | bastardoperator wrote: | See https://semver.org/ for more details. https://0ver.org/ | is fairly popular, and I see https://calver.org/ pretty often | too. | ignoramous wrote: | _0ver_ is parody, right? | taywrobel wrote: | Yes - https://0ver.org/about.html | | "ZeroVer is satire, please do not use it" | mseepgood wrote: | But why is it satire? It makes a lot of sense for | projects that don't want to commit to a stable API. | jonathankoren wrote: | Well there's a joke somewhere. | | Less has my favorite version numbering system. | Sequential. | | Latest stable release: Version 598 | | https://www.greenwoodsoftware.com/less/ | Dylan16807 wrote: | "Tell the user nothing" is your favorite system? | | Especially, like, what if you release a bugfix for a | significantly old version? Do you give it an up-to-date | number? Do you not give it a number at all? | | (Also I see a 581.2 on that page.) | meowface wrote: | My favorite has become just making the version number the | release date. | ViViDboarder wrote: | See CalVer. The date is definitely helpful for something | with fairly stable APIs where breaking changes aren't | really happening. | | Perfect for things like Ubuntu, pytz, and ca- | certificates. | | Less for something like a library who's API could change | and break your implementation. | egeozcan wrote: | AFAICT, its usage is not restricted to generics. It seems to be | suggested to use anywhere you would use interface{}. | | For the release announcement: | https://news.ycombinator.com/item?id=29556646 | mseepgood wrote: | Yes, it's not restricted to generics. But the reason the | alias was introduced is generics. Because they use interfaces | to specify bounds (constraints) for type parameters (bounded | polymorphism): [T fmt.Stringer], [T io.Reader], ... | | So an unbounded type parameter is [T interface{}], or [T any] | when using the shorter alias. It's a type alias / predeclared | identifier defined in the universe scope: | type any = interface{} | eweise wrote: | Couldn't unbounded just be [T]? Why the extra typing? | mseepgood wrote: | No, that would be a parsing ambiguity with arrays. And | the consistency of type parameter lists with normal | parameter lists where types are mandatory is an | additional benefit. | handrous wrote: | Makes it much less likely someone will accidentally | define a type as "any". | MadcapJake wrote: | I am not well-versed in Go, but isn't it because Go | supports specifying multiple parameters with the same | type by just using a comma. Your suggestion would lead to | syntactic ambiguity except when only a single parameter | is provided. Additionally one can provide only types when | parameter values are not needed and this requires there | to be a typename to differentiate between no parameters. | alkonaut wrote: | After generics (coming soon), a proper sum type and then I'll | shut up. | qaq wrote: | same :) maybe also relax rules a bit to allow type elision for | structs in function calls to get python like keyword args. | foo("blah", {option1: true}) would work better than functional | options people use now. | 13415 wrote: | I think they should freeze the language for the next 10 years | or so. | maxk42 wrote: | So now that go has generics and modules, is there an up-to-date | intro for writing cutting-edge Go code for people who are already | pretty familiar with the older styles? | vlunkr wrote: | While it's good to get up-to-date, I don't think anyone should | go re-write code or radically change their programming style to | use generics. There's no need to over-complicate things. | Anywhere that you're either copy-pasting a bunch, or using code | generation might be a good fit for generics. | jcadam wrote: | Just you try not being up-to-date in a coding interview. | saagarjha wrote: | I've found out that it's possible to be _too_ up-to-date | for some coding interviews. | aliswe wrote: | about 10 years ago I had a discussion with an interviewer | (he was actually consultant manager) who said "c# and | Java are exactly the same in terms of runtime | architecture" which I very much disagreed with when | speaking strictly, which wasn't appreciated. | dilyevsky wrote: | Lol so true, go a little overboard with fancy language | features and people think you're a cowboy coder | catillac wrote: | I was in an interview not long after format strings in | Python came out (for example, print(f"Hello, {name}") | rather than print("Hello, %s", name)) and the interviewer | thought I was confusing languages and features, asserted | this fact strongly, and was pretty surprised when it | worked, but I think overall I lost points because the | interviewer lost face. | | C'est la vie. | vlunkr wrote: | As a very casual Python user, I didn't know about that! | that's great. | mseepgood wrote: | There is lots of tutorial-style documentation on modules: | https://go.dev/doc/#developing-modules | | There is also a tutorial on generics: | https://go.dev/doc/tutorial/generics | maxk42 wrote: | I tried doing the modules tutorial a while back but had | difficulty with the directory structure. At some point I | think the "recommended" directory structure became mandatory | and I don't think my personal dev environment ever quite | lined-up with it. Perhaps I should wait another year then buy | a book. | mseepgood wrote: | Modules don't require any particular directory structure, | just a go.mod at the root of your project. | hamburglar wrote: | That's "a particular directory structure" that conflicts | with many already-existing projects. What if I have a | mostly-java project that has a couple bits of go code | buried in it that I want to use as modules? Break it up | into multiple repos for no good reason? No single tool | should be acting like it owns the root directory of my | repo. | mseepgood wrote: | The root of the Go project with the go.mod file doesn't | have to be the root of the repository. | hamburglar wrote: | Doesn't it? Is this new? | mseepgood wrote: | As far as I know this was always possible since modules | were introduced. You just have to prefix the version tags | for Go with the subdirectory in the repo: | "my/sub/directory/vX.Y.Z" | hamburglar wrote: | I swear it didn't always work this way, but I'm happy to | be wrong. | nkozyra wrote: | I like it, interface{} always felt unlike anything else in go | other than structs. | mseepgood wrote: | Why does 'interface{}' feel unlike 'interface{String() string}' | to you? Just because it doesn't have a method? You know that | you can inline non-empty interfaces, too? | func foo(x interface{String() string}) string { | return x.String() } | nkozyra wrote: | I think you (and the other reply) are for some reason | confusing my complaint as functional rather than purely | syntactical. | throwaway894345 wrote: | `interface{}` is just an empty interface, and every type | implements `interface{}` because every type has at least zero | methods. | twsted wrote: | Right decision, in my opinion. I was hoping this. | kbd wrote: | This is fantastic. It'll make Go feel much less weird. eg from | the diff: []interface{}{1, 2.0, "hi"} -> []any{1, | 2.0, "hi"} | | Now that Go is going to have generics, all we need is sugar | syntax for early return on error -- like more modern languages | such as Rust and Zig have -- and Go may finally be pleasant to | program in! | nvarsj wrote: | Yes, please, the iferr pattern drives me nuts. While I built a | few years of my career on golang, I'm absolutely sick of the | language at this point. At least we finally get generics. | hbn wrote: | It's definitely more streamlined, but my concern would be that | newcomers might not understand that it's just an alias. | Learning Go really reframed my concept of what an interface is, | and I thought that using an empty interface to represent "any | type" was kind of ingenious, and helps reinforce its ethos. | | An empty interface can represent any type because every type | inherently implements an interface with no methods. And that's | what Go is all about -- implicitly implementing interfaces. | | If a newbie hops into Go and just starts using "any" I think | they might assume it's a magic type that's at the base of | everything, missing out on the fact that they're still taking | advantage of interfaces. | egeozcan wrote: | I kind of understand what you mean, as it's similar to what | happened with prototypes and the late-comer class syntax in | JavaScript, and in that case, it was a net positive change as | most would probably say. | | Let's see how this plays out. | linkdd wrote: | I cannot wait for the Result monad. | | The state of error handling in Go at the moment is embarrassing | at best. | papito wrote: | People downvote it, but it's true. 2/3 of your Go code is `if | err` blocks. And the way you have to chain the error messages | to make the stack make any kind of sense is just maddening. | Vanclief wrote: | I used to really hate that. After reading this amazing post | https://middlemost.com/failure-is-your-domain I created a | module that makes this bearable | https://github.com/Vanclief/ez | the_duke wrote: | Emulating sum types in languages without pattern matching is | extremely awkward, to the point of being almost useless. | | type Result[T] struct { ok: *T err: error } | | Great, so how do you work with it? | | * You can have a `ok()` getter that returns `*T`. Now you you | need an `if x != nil` | | * `isOk()` + `isErr()` | | * `unwrap() T`, which panics on errors | | * `split() (*T, err)` that splits into separate values, | especially awkward since you both need `if err != nil` AND | dereference the pointer | | That API is more awkward then the status quo, and doesn't buy | you any correctness guarantees because eventually you have to | do an `if x := res.ok(); x != nil` or `x, err := res.split(); | if err != nil {` anyway. | | Pretty much the only convenience you gain are functions like | `map()` or `unwrap_or`, but eventually you always have to | take out the value and without being able to pattern match | you can't get an API that improves correctness much. | | (std::optional in C++ is a great example) | kbd wrote: | > because eventually you have to do... | | Emphasis on _eventually_ instead of at every single | function call. | peoplefromibiza wrote: | you can map on ok which is an alias for map_ok and then | map_err for errors and or_else or_throw etc. | | that's similar to what Java does with the Optional type, | not great, but not bad either | | the alternative is checking for nulls which is worse in any | possibile way | | I usually implement something like Kotlin Result when I | have to code in Java | | with a couple of static helpers to build the result: | Result.success(T) Result.failure(Throwable t) | | https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-result | / | | also Result in Rust has been an inspiration | | https://doc.rust-lang.org/std/result/enum.Result.html | linkdd wrote: | The Rust Result type has: - map / map_err | - and_then / or_else - unwrap / unwrap_or | | And countless of other functions making it very practical | to chain computations without having to pattern match | anything. | | I do the same in Erlang/Elixir. | | In Golang, I need to check every function call, and if I | want to know where an error come from, I need to wrap it in | an errors.New() because no exceptions = no stacktrace | kbd wrote: | > and if I want to know where an error come from, I need | to wrap it in an errors.New() because no exceptions = no | stacktrace | | Zig manages to provide traces with very little overhead: | | https://ziglang.org/documentation/master/#Error-Return- | Trace... | | I am baffled as to why error handling in Go remains _so_ | impoverished. | egeozcan wrote: | I don't see why that wouldn't be possible to implement | now that the generics are here. | linkdd wrote: | Which is exactly why I said: | | > I cannot wait for the Result monad. | | Generics make this possible, and will be a huge | improvement to Go's error handling. | | I'm not saying it will solve everything, but it's a huge | step nonetheless. | Thaxll wrote: | Well it's better than most language with exceptions. | | People makes it a big deal, in reality it's not. | linkdd wrote: | An exception has a stacktrace. This single piece of | information is crucial when you debug and makes handling | errors in Golang embarrassing. | | I rest my case. | mseepgood wrote: | If you want stacktraces just panic. But that's not proper | error handling. | pkaye wrote: | Stack trace was part of a proposal to add to the error | package but it didn't happen. You can use third party | errors packages like https://github.com/pkg/errors which | wrap errors with stack traces. | baby wrote: | This is great, as much as interface{} is not great, it's still | part of the language and really verbose/non-descriptive. I'm | guessing any was a forbidden word? | shadowgovt wrote: | It wasn't so much that `any` was forbidden as that | `interface{}` practically meaning "any value" fell naturally | out of Go's existing type system rules, so there was no need to | introduce another concept. | | But having `any` as syntactic sugar for that concept is a good | idea. | mseepgood wrote: | > I'm guessing any was a forbidden word? | | You mean a reserved keyword? No, 'any' is not a keyword, it's | an identifier (a predeclared identifier). The usual shadowing | rules apply. | brabel wrote: | Their code is full of things like: type fileOps | []any // []T where T is (string | int64) | | Go does not have neither generics nor union types. So people have | to do this kind of thing :( I feel sorry for them. | | Reminds of Java 4 (15 years ago or something) where code was full | of this crap: List /* <String> */ values; | Map /* <String, Object> */ map; | | Some devs spent a whole week doing nothing other than removing | those commented out generic type declarations once Java finally | got generics! | Thaxll wrote: | Go has generics in that commit. | qaq wrote: | 1.18 Beta is out today with Generics | mseepgood wrote: | You're lucky: Go 1.18 Beta 1 was released today, which has | generics. | mikojan wrote: | Craazzyyyyy - ty! | mappu wrote: | Go has had generic List<> and Map<> since before Go 1.0, | though. | | It's really interesting you used those as your examples because | that need was fully met in a type-safe way already, and other | examples are actually much rarer to come by. | comeonseriously wrote: | > I feel sorry for them. | | Oh good grief. There are 32,768 programming languages. People | are free to pick the ones they want to use and nobody wants | your pity. | jwandborg wrote: | Are we wasting that bit to spite us? | [deleted] | gameswithgo wrote: | You could have sum types, and not generics to cover many of | these cases I guess? And then Go could have the error type it | kind of wants to have. | amelius wrote: | > Some devs spent a whole week doing nothing other than | removing those commented out generic type declarations once | Java finally got generics! | | Fast-forwarding to today, could Co-pilot have saved them the | trouble? | vlang1dot0 wrote: | I'm pretty sure sed could have saved them the trouble. | maxpert wrote: | I promised myself I will stay patient, but I think I am on | verge... It's everything I've dreamed off! | uberman wrote: | I love this change/alias | welder wrote: | Good, now we just need the ability to declare function parameters | and return values non-nullable (Forbid passing nil into a | function, and declare a function will never return nil). | | That would get rid of the "panic: runtime error: invalid memory | address or nil pointer dereference" errors. | | https://wakatime.com/blog/48-go-desperately-needs-nil-safe-t... | jchw wrote: | I'd kill for union types as well. | | ... and pattern matching. Maybe just some extensions for | `switch`. | | ... and one of the `try` proposals. | | That having been said... I do appreciate that Go has gotten | where it is today by being radically simple, and that a lot of | extreme care needs to be done to add new features to the | language. It's hard to draw a firm line in the sand. I feel | like all of these features would work great together, though; | it'd enable Go to do something like `Result` in Rust with few | language-level changes. | | I even remain somewhat skeptical about generics, but I am | hopeful. | masklinn wrote: | > I'd kill for union types as well. | | > ... and pattern matching. Maybe just some extensions for | `switch`. | | Go has type switches which are... ok. If it were possible to | "close up" interfaces and type switches took that in account | (match completeness) you'd be done about done, you would not | have the structural / patterned unpacking but that's probably | less of a concern. | Ericson2314 wrote: | C++, Java, JavaScript, Python, Ruby, Go, now all with popular | and/or official type checkers which support generic. | | The normie PL bar is rising, slowly but surely. ___________________________________________________________________ (page generated 2021-12-14 23:00 UTC)