[HN Gopher] Go 1.21 Released
       ___________________________________________________________________
        
       Go 1.21 Released
        
       Author : Mawr
       Score  : 276 points
       Date   : 2023-08-08 15:28 UTC (7 hours ago)
        
 (HTM) web link (go.dev)
 (TXT) w3m dump (go.dev)
        
       | badrequest wrote:
       | I am really excited to start using the new structured logger.
        
         | kiitos wrote:
         | Even after seeing the API, which is enormous and wildly non-
         | intuitive?
        
           | cube2222 wrote:
           | Could you expand what you mean?
           | 
           | When skimming it I mostly saw the common API structure that I
           | usually see in libraries / write myself when I need a logger,
           | so I generally welcome the standardization.
        
             | kiitos wrote:
             | slog defines the concepts of
             | 
             | - Logger -- created by New, accepting a Handler, providing
             | a fixed set of level-based logging methods, asserting
             | concepts of Attrs and Groups, not parameterizable by
             | consumers
             | 
             | - Handler -- with two default implementations, asserting
             | concepts of Attrs Groups and Records, parameterizable by
             | consumers as long as they follow the semantics defined by
             | the interface
             | 
             | - Attr -- arbitrary concept that maps to a k/v pair in a
             | log record
             | 
             | - Group -- arbitrary concept that namespaces a set of k/v
             | pairs in a log record
             | 
             | - Record -- arbitrary concept that requires a timestamp
             | (expensive to compute), a level (one of a specifically
             | defined enum which cannot be changed), and a PC stack
             | pointer (obvious issues there)
             | 
             | I've never seen a logging package which meets these
             | requirements.
        
           | badrequest wrote:
           | I've seen the API, and it's not either of those things if
           | you've already used a structured logger?
        
         | iamcalledrob wrote:
         | Yes!
         | 
         | Logging always felt like something that (1) almost every
         | project needs, and (2) there are too many 3rd party packages,
         | with no "de facto" choice.
         | 
         | This is particularly painful when working with 3rd party
         | library code. There's a high chance that the consumer of
         | library code uses a different logging package to the library
         | author.
         | 
         | Having structured logging in the stdlib is fantastic, because
         | now there is a "go way" to this that libraries can use.
        
           | eberkund wrote:
           | Does this mean that all the third party logging packages will
           | likely die out in the future? Or will they likely implement
           | adapters to be compatible with the std interface?
        
             | cratermoon wrote:
             | From the original proposal <https://go.googlesource.com/pro
             | posal/+/master/design/56345-s...>
             | 
             | 1 "We expect existing logging packages to coexist with this
             | one for the foreseeable future."
             | 
             | 2 "We expect that this proposal's handlers will be
             | implemented for all popular logging formats and network
             | protocols, and that every common logging framework will
             | provide a shim from their own backend to a handler"
        
       | mdaniel wrote:
       | seems the submissions for "Go $v Released" have been 50/50
       | pointing to the doc url versus the blog url:
       | https://go.dev/blog/go1.21
        
       | ydnaclementine wrote:
       | I'm a recent convert and enjoying it quite a bit for webdev.
       | There's lots of books out there, but I found let's go and let's
       | go further to be great project based books
        
         | beeburrt wrote:
         | I'm a recent convert as well. Thanks for the recommendation,
         | I'll look them up.
        
       | hwc wrote:
       | I'm looking forward to the log/slog package. I might start
       | switching over from our homegrown solution next week.
        
       | lenkite wrote:
       | No basic Map or Filter functions in the new slices pkg. Sadness.
        
         | empath-nirvana wrote:
         | I think it's a reasonable first pass at implementing generic
         | functions.
         | 
         | I'd love to see Map/Filter/Reduce, but starting with the
         | simplest set of generic functions and getting people
         | comfortable with them is probably a good idea.
         | 
         | Go idiomatically is very imperative and introducing a new
         | programming style at the same time as introducing generics
         | might be too much change at once.
         | 
         | I'd also like to see an option and a result type at some point
         | so we can stop doing nil checks all over the place.
        
         | morelisp wrote:
         | If we're lucky they won't add them until they have some halfway
         | decent fusion working in the compiler.
        
         | masklinn wrote:
         | Makes sense given the idea of getting some form of iterators
         | support into the language, collection-specific HoFs means more
         | duplication and worse composition as the intermediate
         | collections generally need to be allocated on every step, and
         | often can't be optimised away because you're stuck with your
         | defined order of evaluation.
        
       | febstar wrote:
       | Seems to be the smallest Go release yet (at least since 1.4). I
       | wonder how the binary size was reduced in the recent two
       | versions?                  1.21    63MB        1.20    95MB
       | 1.19   142MB        1.18   135MB        1.17   129MB        1.16
       | 123MB        1.15   116MB        1.14   118MB        1.13   114MB
       | 1.12   121MB        1.11   121MB        1.10   114MB        1.9
       | 98MB        1.8     86MB        1.7     78MB        1.6     81MB
       | 1.5     74MB
       | 
       | (linux-amd64 archives from https://go.dev/dl/)
        
         | 38 wrote:
         | Other two comments are wrong. The correct answer is that the
         | compiler now builds everything on demand if it's not already
         | built. This now includes the standard library as well.
         | Previously built versions of standard library modules were
         | being shipped.
        
         | FiloSottile wrote:
         | Long term intentional effort: https://go.dev/issue/27151
        
           | tough wrote:
           | All I could find for context about what caused it (which is
           | not reflected in that issue)
           | 
           | > Go command The directory $GOROOT/pkg no longer stores pre-
           | compiled package archives for the standard library: go
           | install no longer writes them, the go build no longer checks
           | for them, and the Go distribution no longer ships them.
           | Instead, packages in the standard library are built as needed
           | and cached in the build cache, just like packages outside
           | GOROOT. This change reduces the size of the Go distribution
           | and also avoids C toolchain skew for packages that use cgo.
           | 
           | https://tip.golang.org/doc/go1.20
        
         | Someone wrote:
         | Possibly compiler/linker improvements. For example, FTA:
         | 
         |  _"In Go 1.21 the linker (with help from the compiler) is now
         | capable of deleting dead (unreferenced) global map variables,
         | if the number of entries in the variable initializer is
         | sufficiently large, and if the initializer expressions are
         | side-effect free."_
         | 
         | There also may be differences in debug symbols in the various
         | binaries.
        
       | candiddevmike wrote:
       | Stuff keeps moving out of the standard lib related to crypto.
       | First was PGP, now elliptic. Why doesn't Go want to provide
       | stdlib crypto stuff?
        
         | FiloSottile wrote:
         | Go is absolutely committed to the cryptography standard
         | library. What's happening is that we're deprecating legacy
         | protocols and APIs to invest resources on packages that better
         | align with the Cryptography Principles [0].
         | 
         | In particular, crypto/elliptic was an unfortunate API that has
         | been deprecated in favor of the new crypto/ecdh. Most
         | applications can migrate (on their own time, as we don't break
         | backwards compatibility even for deprecated packages) and get
         | better security and performance. (A very small portion of
         | applications might need lower level applications, in which case
         | they can use third party modules based on the stdlib internals,
         | like filippo.io/nistec.) You can read more on my Go 1.20 [1]
         | and Go 1.21 [2] posts.
         | 
         | [0]: https://golang.org/design/cryptography-principles [1]:
         | https://words.filippo.io/dispatches/go-1-20-cryptography/ [2]:
         | https://words.filippo.io/dispatches/go-1-21-plan/
        
         | chrsig wrote:
         | my bet is it has something to do with Filippo Valsorda having
         | left google, but that's pure speculation on my part.
         | 
         | https://github.com/FiloSottile
        
           | FiloSottile wrote:
           | Nope :) I'm still a maintainer, and actually happen to be the
           | one that drove those two deprecations.
           | https://words.filippo.io/full-time-maintainer/
        
             | chrsig wrote:
             | Glad to have my wild speculation disproven :) And glad that
             | becoming a full time independent maintainer is working out
             | for you!
             | 
             | Though, in hopes you see this, I have to ask: Is there any
             | sort of plan for if you wanted to step down from a
             | maintainers role of the go crypto packages?
             | 
             | You're sort of known as "the" go crypto person, so I guess
             | it occurred to me that your bus factor might be quite high.
             | Any thoughts you can give to assuage fears in that regard?
             | Is there anything the community can do to share the load,
             | short of becoming cryptography experts?
        
         | kyrra wrote:
         | Two reasons I can think of:
         | 
         | 1) speed to update it in the case of a bug / security issue.
         | 
         | 2) backwards compatibility.
         | 
         | Getting a new Go release out is likely a lot more time
         | consuming than bumping up the crypto library outside of there.
         | And those libraries do not require full backwards compatibility
         | compared to the Go standard library. So they can do breaking
         | changes if need back without breaking the Go contract.
        
           | eatonphil wrote:
           | For 1) they create patch releases of Go versions fairly
           | often. So I don't think that makes sense.
        
             | mseepgood wrote:
             | Perhaps they would prefer not to create them so frequently.
        
       | h1fra wrote:
       | adding min/max to a language made 10 years ago is kinda crazy
       | when you think about it. Really looking log/slog package, it
       | seems neat and was deeply needed.
        
         | jakear wrote:
         | Hah, I just went down a whole rabbit hole on super-logarithms
         | and tetration wondering why you found it so critical as to
         | warrant standard-library inclusion.
        
         | thiht wrote:
         | Note that min/max were already available in the math package,
         | but they're a bit inconvenient to use (lots of casting to do)
        
       | 015a wrote:
       | The log/slog package is huge. I'm super happy to see them start-
       | again to express opinions and solve more problem with just the
       | standard library; and I hope to see more of it. This was Go's
       | Thing at 1.0; you could build a production ready, large scale
       | HTTP service with nothing but the standard library; and,
       | probably, a structured logging package like Zap. Now; looks like
       | we may not need it!
       | 
       | If anyone on the Go team is reading this; thanks! And, as hacker
       | news must always be the armchair commentator, if I may ask for an
       | addition in go 1.22: encoding/yaml. Build it in. Go and YAML are
       | the languages of devops, and I've written so many scripts with
       | JSON as a configuration file only because Go has a JSON parser
       | built-in, but not YAML.
        
         | liggitt wrote:
         | > if I may ask for an addition in go 1.22: encoding/yaml
         | 
         | FYI, encoding/yaml was recently requested, and was declined in 
         | https://github.com/golang/go/issues/61023#issuecomment-16106...
         | , for reasons I largely agree with.
         | 
         | (I work for Google but not on Go)
        
       | pojzon wrote:
       | Im still looking for a language that will solve my biggest issue:
       | 
       | - dependency hell..
       | 
       | Recently had to update unmaintained project by 5 dependency
       | versions higher. It was so painful with GO.
        
         | ParetoOptimal wrote:
         | I don't use Go a lot anymore, but I sometimes use Nix's
         | buildGoModule:
         | 
         | https://nixos.wiki/wiki/Go
         | 
         | Oh wait... You mean because of breaking language changes?
        
         | hu3 wrote:
         | Vendoring might help with building old code. It stores a copy
         | of depencies in a directory which you can include in git.
         | https://go.dev/ref/mod#vendoring
         | 
         | As for upgrading old libraries which might have broken
         | backwards compatibility, I can't offer much.
        
           | bananapub wrote:
           | how would that help with building old code? is old code often
           | unavailable upstream?
        
         | randomdata wrote:
         | Needing to change an entire dependency version (let alone four
         | more versions) is a sign of human error.
         | 
         | It is unlikely that software will fix a bumbling human. No
         | matter how hard it tries, humans will always find some new way
         | to do something stupid.
        
       | adrianmsmith wrote:
       | Re: https://github.com/golang/go/wiki/LoopvarExperiment
       | 
       | I've mainly used Java which doesn't suffer from this particular
       | problem. But I've often heard Java criticized on the grounds it
       | captures values not variables, and that most other languages
       | apparently capture variables. I remember learning Lisp at uni and
       | being taught that it captured variables, for example.
       | 
       | So do other languages suffer from this problem as well? How do
       | they deal with it?
        
         | assbuttbuttass wrote:
         | In fact most languages suffer from this, but it's more acute in
         | go because of how easy it is to create closures and threads.
         | 
         | For example, what does the following Python code print?
         | funcs = list()         for i in range(10):
         | funcs.append(lambda: print(i))         for f in funcs:
         | f()
        
           | mdaniel wrote:
           | I didn't know the answer to this, but it seems like this
           | actually behaves closer to `funcs.append("""print(i)""")`
           | since                   funcs = list()         for i in
           | range(10):             funcs.append(lambda: print(i))
           | del i         for f in funcs:             f()
           | 
           | actually NameErrors during f() so I don't think it is
           | actually closing over the i as much as the i was left in
           | scope and the code was seemingly lazy evaluated
        
             | InfamousRece wrote:
             | Right. In this example lambda does not capture i at all.
             | You would need something like
             | funcs.append(lambda i=i: print(i))
        
             | germandiago wrote:
             | prints all 9s.
        
           | cutler wrote:
           | It's called late binding and some Pythonistas actually
           | consider it a feature.
        
           | [deleted]
        
           | dragonwriter wrote:
           | > most languages suffer from this
           | 
           | Specifically, I think, any language with closures where the
           | loop variable exists in a scope enclosing all loop iterations
           | with a value that is updated each iteration rather than a
           | fresh variable in a scope local to each loop iteration has
           | this problem.
           | 
           | In Ruby this wouldn't affect idiomatic looping methods like
           | #each, but would seem likely to affect the less-idiomatic for
           | loop, which is built on #each but has the control variable in
           | the surrounding scope. (Not 100% certain how it desugars
           | though.)
        
             | masklinn wrote:
             | > In Ruby this wouldn't affect idiomatic looping methods
             | like #each, but would seem likely to affect the less-
             | idiomatic for loop, which is built on #each but has the
             | control variable in the surrounding scope. (Not 100%
             | certain how it desugars though.)
             | 
             | I don't know how it desugars, but it is indeed affected
             | when using `for...in`
        
           | sharno wrote:
           | Interesting, didn't think about closures in Python before. It
           | seems that JS has the same behavior.
           | 
           | Java forces you to final copy the variable.
        
             | agumonkey wrote:
             | I lost track of ES scoping rules but apparently `for (var i
             | ...) { ... }` doesn't capture (legacy behavior) while `for
             | (let i ...) { ... }` will.
        
               | mdaniel wrote:
               | I don't think that's limited to just `var`, as a `let`
               | outside of the `for` will do the same
               | let funcs = [];         ;(() => {             let i;
               | for (i = 0; i < 10; i++) {
               | funcs.push(function() { console.log('i=',i); })
               | }         })()         for (let f of funcs) {
               | f.call(null);         }
               | 
               | (I used an IIFE to hide the "let i" from the .call to
               | ensure it wasn't late binding to the name like the python
               | example did)
        
               | agumonkey wrote:
               | you think they have a special rule in `for (let .. of ..
               | ) ... ` then ?
        
         | kazinator wrote:
         | In some cases, Common Lisp makes it implementation-defined.
         | E.g. in (dolist (item list) ...) it is implementation-defined
         | whether _x_ is a freshly bound lexical, or a stepped variable.
         | 
         | In Lisp, you can easily write macros that have whatever
         | semantics you want. You can easily write a _my-dolist_ which is
         | like _dolist_ but freshly binds the item variable for every
         | iteration, and next to it write a _my-dolist2_ which assigns a
         | single variable.
         | 
         | In languages like Go, the providers of your language provide
         | all the syntax from behind a wall, and make these decisions for
         | you. Knights in shining armor duke it out on the rooftop of an
         | ivory tower, while lower vassals blog incessantly about the
         | important work being done and decisions being made.
         | 
         | By the way, MacCarthy's ancient Lisp (Lisp 1, Lisp 1.5) didn't
         | have lexical scope, so it would not have made any difference
         | whether each iteration stepped the variable with _setq_ or
         | bound it with _let_. There would just be the one dynamic
         | variable in all cases, not captured by any lexical closures
         | (those being nonexistent). You 'd want to bind it at least once
         | with _let_ so the prior value is restored when the loop is
         | done.
         | 
         | In Common Lisp, if we use a special variable as the loop
         | variable, it likewise won't make a difference whether it is
         | stepped or bound each time, since the binding isn't lexical.
        
           | germandiago wrote:
           | Macros is exactly what makes Lisp a one-man only language for
           | every person unless you are really careful.
           | 
           | That, combined with the fact that things are often poorly
           | documented is what IMHO ruins the language ecosystem.
           | 
           | I want to like Lisp and I love its interactivity but I find
           | the language a bit more "construction material" language than
           | a ready-to-use immediately language. What is bad about that
           | is exactly what you mention: everyone will come up with a set
           | of macros that others cannot fully grasp.
        
             | kazinator wrote:
             | A poorly documented and tested libraries will give you
             | problems no matter what kinds of entities it defines.
             | Someone who writes macros that nobody can easily grasp will
             | also write functions nobody can easily grasp.
             | 
             | If you have to reverse engineer someone's macros, you have
             | all of the following going for you
             | 
             | The macros run at compile time and then go away (unless the
             | program is based on a dynamic compiling paradigm). They
             | have no behaviors at run-time; their generated code does.
             | No matter how complicated the macro, you can just run it
             | and capture the output code, and through multiple examples
             | get an understanding of what it's doing.
             | 
             | If someone writes a buggered function, you may have to end
             | up debugging it on a target system, perhaps an embedded
             | one.
             | 
             | The sky is the limit there. If it's a function in a kernel,
             | you may have to debug some race condition between it, some
             | interrupt handler and a piece of hardware.
             | 
             | No such thing ever happens when debugging a macro itself.
             | 
             | A macro doesn't interact with complex application state,
             | because that doesn't exist. You never have to attach some
             | gigabyte database and get some objects into the right state
             | before reproducing some expansion problem in a macro. Code
             | generated by a macro could be involved in a problem like
             | that, possibly as a root cause, but tracing through the
             | macro itself isn't.
             | 
             | The people who write awful macros are usually not smart
             | enough to do anything that is actually hard to understand.
             | The problems you will find are lack of hygiene, multiple
             | evaluations and such.
        
               | germandiago wrote:
               | > A poorly documented and tested libraries will give you
               | problems no matter what kinds of entities it defines.
               | Someone who writes macros that nobody can easily grasp
               | will also write functions nobody can easily grasp
               | 
               | Lisp makes this so easy to write macros and they have
               | been promoted to be the "my-powerful-dsl-is-the-right-
               | way-to-solve-a-problem" that, IMHO, it works actively
               | against team work unless it is really well-dcumented.
               | Now, mix that with the fact that code is not usually
               | deeply documented and you get a cultural problem into the
               | whole ecosystem.
               | 
               | > A macro doesn't interact with complex application
               | state, because that doesn't exist. You never have to
               | attach some gigabyte database and get some objects into
               | the right state before reproducing some expansion problem
               | in a macro. Code generated by a macro could be involved
               | in a problem like that, possibly as a root cause, but
               | tracing through the macro itself isn't
               | 
               | Tracing the macro can be as difficult as its expansion.
               | If it gets obtuse it will add a lot of time to your
               | workflow. I know they are powerful but it is probably the
               | last feature I would use in a team, with a lot of care,
               | and for trivial things or for really justified cases and
               | with good documentation. If your code is full of macros,
               | forget about readability, you threw it out through the
               | window.
               | 
               | > The people who write awful macros are usually not smart
               | enough to do anything that is actually hard to
               | understand. The problems you will find are lack of
               | hygiene, multiple evaluations and such
               | 
               | Because writing macros is not that simple in the first
               | place. I find much easier to write regular code and use
               | the well-known macros than grasp anonymous macro code.
               | There are things you can only do with macros though, like
               | lazy evaluation. But macros must be managed with extra
               | care. For example, maybe instead of a macro it is better
               | to use a higher order function with a closure to keep the
               | code understandable than burying things in layers of
               | macros.
        
         | masklinn wrote:
         | Note that there are two separate components to the issue:
         | 
         | 1. the interaction between mutable locations and closures
         | 
         | In most languages with mutable bindings, if you close over a
         | variable you're closing over a "cell" and will see future
         | modifications to it. This is the case in Go, Python, Ruby,
         | Javascript, C#, ...
         | 
         | A few languages avoid it e.g.
         | 
         | - Java, not because it "captures values" but because it only
         | allows capturing "final" variables so you can't update the
         | bindings (you can still mutate in place when capturing
         | reference types)
         | 
         | - C++, because you have to specify the capture mode and it'll
         | only be affected if you capture by reference (which you
         | wouldn't do for a loop variable), so the likelihood of hitting
         | this issue is pretty low
         | 
         | - Rust, because even if you capture by reference you can't
         | modify a binding with an outstanding reference
         | 
         | 2. the scoping of loop variables, if you're capturing the loop
         | variable but each iteration has a different version of the loop
         | variable then you don't really mind too much, because each
         | closure will capture its own loop variable, this doesn't fix
         | the above issue but it does fix the most common occurrence of
         | it
         | 
         | That's what Go is doing, other languages which have done that
         | are C# (when using a `foreach` loop), Javascript (when using
         | `let` or `const` for the loop variable), ...
         | 
         | Also Ruby, kind-of: using the `each` method for iteration is
         | very common, and since then the loop variable is a parameter to
         | the block it's basically a per-iteration local, "for...in"
         | still has the issue. I guess C# also has that when using the
         | linq ForEach method but I don't know how common _that_ is.
        
           | munificent wrote:
           | Probably worth pointing out that C# used to have Go's
           | behavior and they changed it (a rare breaking language
           | change) specifically because it was such a notorious pitfall.
           | 
           | I think Go is doing the right thing here. I'm somewhat
           | surprised they didn't always do this. (Dart has created a new
           | loop variable for each iteration all the way back since
           | before 1.0.)
        
             | masklinn wrote:
             | Similarly in javascript, "let" and "const" we're added
             | specifically with block and per-iteration scoping, because
             | the ever increasing popularity of callbacks for async was
             | making the function-scoped var more infuriating every day.
        
       | renewedrebecca wrote:
       | How comfy is go for general native performance coding tasks?
       | Basically looking for a C/C++ replacement. (I don't really like
       | how Rust looks syntactically, and prefer GC over manual memory
       | management.)
        
         | stevemk14ebr wrote:
         | Look into Nim or Zig instead if you're coming from C++
        
           | germandiago wrote:
           | I would also recommend to take a look at D.
        
         | [deleted]
        
         | kristianp wrote:
         | If you're looking for the absolute top speed, it's not as fast
         | as C++ or rust. Assembly functions can't be inlined, for
         | example. But go allows you to control your memory structures
         | and that gets you good cache utilisation, compared to, say
         | java. Go is plenty fast enough for most applications.
        
         | lytedev wrote:
         | I'm not an expert at all, but I wouldn't. I would reach for nim
         | or even zig before go. But it depends on what you're building,
         | I'm sure!
        
         | repeekad wrote:
         | Personal experience is great, though for large projects C++ is
         | definitely more robust.
         | 
         | Really like how go handles parallelism and creating threads.
        
           | germandiago wrote:
           | I think Go is a really good fit to write async servers. Its
           | set of features make it a killer language for that use case.
        
           | assbuttbuttass wrote:
           | I'm curious what are some of the reasons C++ is better for
           | large projects?
        
         | pjmlp wrote:
         | As C replacement, I would say relatively ok, specially if you
         | look at it from the point of view of Limbo in Inferno.
         | 
         | As C++ replacement, I would stay is too lacking in features.
         | For that I would rather reach out to C#, D, Java (with
         | OpenJ9/Graal), or even Haskell/OCaml.
        
       | KolmogorovComp wrote:
       | > When printing very deep stacks, the runtime now prints the
       | first 50 (innermost) frames followed by the bottom 50 (outermost)
       | frames, rather than just printing the first 100 frames. This
       | makes it easier to see how deeply recursive stacks started, and
       | is especially valuable for debugging stack overflows.
       | 
       | This is a very nice QoL improvement, I wish more languages made
       | the change.
        
         | michaeljx wrote:
         | 100+ frames deep? I am a python dev, is that normal in Go?
         | Sounds atrocious
        
           | geodel wrote:
           | Well its normal in Java and from what I have seen despite
           | being advised against it a lot of folks coming from Java to
           | Go have brought along Java style heavily abstracted code,
           | framework first design patterns with them. This can
           | definitely lead to very deep stack traces.
        
           | masklinn wrote:
           | Python will also do something like that, specifically it
           | snips out repeated lines in self-recursive calls:
           | https://github.com/python/cpython/issues/71010
           | >>> a()         Traceback (most recent call last):
           | File "<stdin>", line 1, in <module>           File "<stdin>",
           | line 3, in a           File "<stdin>", line 3, in a
           | File "<stdin>", line 3, in a           [Previous line
           | repeated 894 more times]           File "<stdin>", line 2, in
           | a           File "<stdin>", line 2, in b           File
           | "<stdin>", line 2, in c           File "<stdin>", line 2, in
           | c           File "<stdin>", line 2, in c           [Previous
           | line repeated 97 more times]         RecursionError: maximum
           | recursion depth exceeded
           | 
           | Sadly it's not smart enough to handle indirect recursion, so
           | in those cases you get a thousand lines of garbage.
        
           | eyelidlessness wrote:
           | "This makes it easier to see how deeply recursive stacks
           | started, and is especially valuable for debugging stack
           | overflows."
           | 
           | Mistakes are normal in any language. Debugging an infinitely
           | deep recursion can be challenging in most.
        
       | telotortium wrote:
       | > Go 1.21 now defines that if a goroutine is panicking and
       | recover was called directly by a deferred function, the return
       | value of recover is guaranteed not to be nil. To ensure this,
       | calling panic with a nil interface value (or an untyped nil)
       | causes a run-time panic of type *runtime.PanicNilError.
       | 
       | > To support programs written for older versions of Go, nil
       | panics can be re-enabled by setting GODEBUG=panicnil=1. This
       | setting is enabled automatically when compiling a program whose
       | main package is in a module with that declares go 1.20 or
       | earlier.
       | 
       | An explanation of why this change was implemented is contained in
       | the description of the implementing change, https://go-
       | review.googlesource.com/c/go/+/461956. In short, calling
       | `panic(nil)` before would make `recover` return nil, which is
       | what's returned when there is no panic. `recover` doesn't have a
       | `panicArg, ok = recover()` return value variant, so they fixed it
       | this way.
        
       | rcme wrote:
       | Is it just me or is the new import initialization algorithm n^2
       | in the worst case? Surprised by that.
        
       | rickette wrote:
       | The backwards compatibility promise (as always) is really nice.
       | Java/JVM is the only other language/platform that I can think of
       | that does more or less the same. Using both extensively by the
       | way.
        
         | mseepgood wrote:
         | Yes, I like to build my castles on solid ground rather than on
         | quicksand.
        
         | germandiago wrote:
         | C++ takes compatibility very serious. Though it has ABI stuff
         | here and there you need to deal with due to its fully native
         | AOT compilation nature.
        
         | greggyb wrote:
         | Common Lisp has been standardized for longer than Java's life.
         | 
         | Also in the lisp world, Clojure has a fastidious dedication to
         | backward compatibility.
         | 
         | Perl 5 has maintained backward compatibility (though I am not
         | certain if it is 100% compatible) by putting changes behind
         | flags.
        
         | beezlewax wrote:
         | Pretty sure Rust has this too right?
        
           | kiitos wrote:
           | Rust is definitely not backwards-compatible in the sense that
           | Go is backwards-compatible.
        
             | stusmall wrote:
             | How so? What breaking changes have you hit? It has the same
             | guarantee and takes it extremely seriously. The only code I
             | know of that compiled on a stable post-1.0 compiler but
             | broke was because of bugs, even those cases are rare.
        
               | kiitos wrote:
               | I think std async is about as good an example as any.
        
               | stusmall wrote:
               | Do you mean async-std as in the 3rd party crate?
        
       | predictabl3 wrote:
       | Helloooooo riscv64-linux support! EDIT: lol this fickle site. Not
       | my fault they didn't publicize the fact that they're now
       | publishing riscv64 binary releases (allowing distros to bootstrap
       | riscv64 targets now).
        
         | mholt wrote:
         | Not sure why you're getting downvoted. We got a pull request to
         | add this to our Caddy build process today:
         | https://github.com/caddyserver/caddy/pull/5720
        
       | j16sdiz wrote:
       | The "Loopvar" experiment looks like backward compatibility
       | nightmare. As confusing as the existing behaviour could be, the
       | new experiment is asking for trouble.
        
         | kristianp wrote:
         | For those wondering:
         | 
         | https://github.com/golang/go/wiki/LoopvarExperiment
        
         | tsimionescu wrote:
         | The existing behavior is _extremely_ unlikely to be helpful,
         | even accidentally. I will be shocked if anyone actually hits a
         | problem related to this change. It may well fix more bugs than
         | it introduces.
        
         | philosopher1234 wrote:
         | It's a breaking change, but rsc did very thorough testing of
         | publicly available code and internal Google code and found
         | essentially only bug fixes. But I think the risk is why this is
         | an experiment and not a straight up change. Also, the new
         | behavior would only be enabled on modules that are marked as Go
         | 1.22 or above, not program globally, iiuc. So to me, this is
         | very thoughtfully planned and unlikely to be any kind of
         | nightmare
        
           | [deleted]
        
         | tapirl wrote:
         | For `for-range` loops, it looks the benefits of this change are
         | more than the drawbacks.
         | 
         | For `for ...; ...; ...` loops, personally, I think the
         | conclusion is the inverse.
         | 
         | One breaking case:                   func main() {
         | defer println()          for counter, i := 0, 0; i < 3; i++ {
         | defer func() {            counter++            print(counter)
         | }()          }         }
         | 
         | It will print 111 when the change is made.
         | 
         | More surprising cases:
         | https://github.com/golang/go/issues/60078#issuecomment-15443...
        
           | tedunangst wrote:
           | Why don't any of the examples of surprise breakage link to
           | real code relying this behavior?
        
         | icholy wrote:
         | C# did the same thing in 5.0
         | https://ericlippert.com/2009/11/16/closing-over-the-loop-var...
        
           | plorkyeran wrote:
           | When C# shipped this change I was working on a large C#
           | codebase and we were very worried about this. After auditing
           | the entire codebase and checking every for loop, we found two
           | pre-existing bugs in code which expected the 5.0 behavior and
           | zero places which relied on the old behavior.
           | 
           | Everyone that I've ever talked to who went through the
           | transition has a similar story. In practice no one even
           | incidentally relied on the old behavior. Go rolling it out as
           | an experimental opt-in feature is a good idea, but it'll
           | probably turn out to be unnecessarily cautious and they could
           | have gotten away with just unconditionally enabling it.
        
           | tapirl wrote:
           | C# only did this on `foreach` loops, not on traditional `for`
           | loops. Go plans to do this on both (`for-range` loops and
           | traditional `for` loops).
        
         | jjnoakes wrote:
         | > no programs will change behavior due to simply adopting the
         | new Go toolchain
         | 
         | Seems like they thought about that. I think it's a good change.
        
         | masklinn wrote:
         | Is it? The experiment is just that, a way to test your packages
         | for breakage, the proposition to opt in via langfile is similar
         | to Rust edition systems which work fine.
         | 
         | Way back when C# actually went through that change
         | _unconditionally_ (LangVersion was not a thing yet), and there
         | was barely any breakage.
        
         | latchkey wrote:
         | Forgetting to add `foo := foo` in a for loop tends to be bigger
         | trouble. =)
        
       | simonz05 wrote:
       | Felix Geisendorfer did a bunch of work to improve continuous
       | profiling performance [1].
       | 
       | [1]: https://blog.felixge.de/waiting-for-go1-21-execution-
       | tracing...
        
         | aktau wrote:
         | Indeed, this is awesome work.
        
       | levischoen wrote:
       | wow this was a very "we made everything a little better", lot of
       | thanks to the golang devs
        
       | WhereIsTheTruth wrote:
       | > Go 1.21 improves build speed by up to 6%, largely thanks to
       | building the compiler itself with PGO.
       | 
       | Go already compile fast, and it still gets faster release after
       | release, love it!
        
       ___________________________________________________________________
       (page generated 2023-08-08 23:02 UTC)