[HN Gopher] Go 1.18 Beta 1 is available, with generics
___________________________________________________________________
Go 1.18 Beta 1 is available, with generics
Author : pcw888
Score : 196 points
Date : 2021-12-15 10:30 UTC (12 hours ago)
(HTM) web link (go.dev)
(TXT) w3m dump (go.dev)
| yannoninator wrote:
| A better xmas present than anything I've ever received. bravo!
| zerr wrote:
| I hope the next big thing is a proper error handling instead of
| if-hell.
| Cthulhu_ wrote:
| There was a spurt of this before they seriously went to work on
| generics, and the conclusion was "actually, it's fine the way
| it is". There's huge discussions on the matter as well as
| various proposals, but they all came with caveats that, in the
| end, weren't considered a significant improvement.
|
| That said, with generics, it should be possible to change to
| the 'Either' style [0] of error handling. And with another
| compiler feature to be added, er, 'exhaustive switch/case' or
| whatever you want to call it, they can make it a compiler error
| to not handle the error case. That said, I don't see the
| language developers or community making it a standard anytime
| soon.
|
| The current style of error handling doesn't hurt enough. It's
| verbose and repetitive, sure, but if the alternative is
| something clever or magic, it's not the way to go.
|
| [0] https://www.scala-
| lang.org/api/2.13.6/scala/util/Either.html
| 5e92cb50239222b wrote:
| Give it 20 more years of evolution (considering we're talking
| about Go, probably 70 years), and we get another C++. A Google
| of the future (let's call it Scroogle) starts another language
| that can be used by recent graduates that have no idea about
| what they're doing to write mountains of JSON fiddling
| boilerplate. Rinse and repeat.
| nauticacom wrote:
| Hey, don't be so pessimistic. We'll probably have another
| serialization protocol by then.
| ernst_klim wrote:
| I think people are constantly focusing on the wrong target here
| though.
|
| The main problem of error handling in Go is not the tediousness
| of writing if err != nil {}
|
| after each function (it's not nice but bearable).
|
| The main problem is how hard to actually process errors.
|
| In Go, there are three types of errors: custom structs with
| contextual info, predefined error constants of type stringError
| aka sentinels, and wrapped stringErrors, produced in-place by
| fmt.Errorf.
|
| The first ones can be matched by type coersion or errors.As
| function. The second ones can be compared with == operator. The
| last ones can be either parsed by regex, or matched by the
| error they wrap and then unwrapped.
|
| Oh, and the signature is nearly always just error, so basically
| to process errors gracefully you have to read the docs for each
| function instead of just looking at the signature.
|
| It's so extremely inconvenient and tedious so nearly nobody
| process errors in Go, despite what language creators say.
| People either return error to the top of the callstack, maybe
| wrapping it in additional string, thus emulating poor man's
| exceptions without stack traces, or panic in-place. Nearly
| nobody catches and matches errors, as many in C++, Java, Scala
| or OCaml|Haskell world do.
| lowmagnet wrote:
| This is the biggest complaint after generics, and there are a
| few proposals to dynamically resolve it in either libraries or
| language features. These proposals are in the go2drafts
| section, but keep in mind that this is where generics were
| originally placed on the timeline. Yet here we are with a
| backward-compatible change to the language in the sub-2.0
| version of the language.
| laerus wrote:
| > The key point here is our programmers are Googlers, they're not
| researchers. They're typically, fairly young, fresh out of
| school, probably learned Java, maybe learned C or C++, probably
| learned Python. They're not capable of understanding a brilliant
| language but we want to use them to build good software. So, the
| language that we give them has to be easy for them to understand
| and easy to adopt.
| honkycat wrote:
| I'm going to start writing functional Golang and none of you can
| stop me
| neillyons wrote:
| Cool. Does anyone know of libraries that are using Go generics
| yet?
| quantum_state wrote:
| Nice!
| mfrw wrote:
| A quick[0] 13min video on generics by Ian Lance Taylor.
|
| [0]: https://www.youtube.com/watch?v=nr8EpUO9jhw
| e12e wrote:
| Thank you. I'm not a gopher - but shouldn't code-gen be
| mentioned as an alternative too? Or is that used for something
| else?
| dragandj wrote:
| So now it turns out that generics are good?
| mfrw wrote:
| It remains to bee seen, meanwhile Rob Pike did comment[0], we
| should refrain from changing libraries in 1.18 immediately
| after generics are in.
|
| "The reason is simple and compelling: It's too much to do all
| at once, and we might get it wrong."
|
| [0]: https://github.com/golang/go/issues/48918
| Cthulhu_ wrote:
| > It's too much to do all at once, and we might get it wrong.
|
| If only people realized this about most software projects.
| There's a lot of hubris and under-estimation in software
| engineering.
| rob74 wrote:
| The Go team's stance on generics has never been "generics =
| bad", but "generics have advantages and disadvantages, and if
| we find an implementation which finds a good compromise between
| the advantages and disadvantages, we will do it". Which they
| now did. Let's hope it really turns out to be a good
| compromise...
| zerr wrote:
| It was due to the arrogance and incompetence of a couple of
| ex-AT&T authorities in the team.
| hu3 wrote:
| Is there a source for that?
|
| I ask because instances I read from the team were in the
| direction of: "We will gather enough use cases to decide on
| the matter".
| gadflyinyoureye wrote:
| While the GP was a bit...harsh, the main reason people
| have that view is generics, as a problem space, were
| solved. Java's way was published years ago. As was
| .NET's. Other languages exist which have some form
| generics. The argument of "gather enough use cases to
| decide on the matter" feels like a punt given the use
| cases already exist and were known in the industry for
| the past 30 years.
| hu3 wrote:
| Perhaps. But in hindsight, Go's generics implementation
| turned different enough to warrant benefit of the doubt
| in my opinion. A notable difference is that Go interfaces
| are implicit while C# and Java are explicit and that
| affects Go generics.
| rob74 wrote:
| The problem space may seem solved, but apparently it's
| still not as easy as it looks from the outside. You don't
| have to take my word for it, Cthulhu_ linked a comment by
| Russ Cox (a major contributor to Go) from a few years ago
| above: https://news.ycombinator.com/item?id=9622417
|
| > _We have spoken to a few true experts in Java generics
| and each of them has said roughly the same thing: be very
| careful, it 's not as easy as it looks, and you're stuck
| with all the mistakes you make._
| gadflyinyoureye wrote:
| I agree. From my Java experience most people don't do a
| lot with them. List<Something> and the like. It makes
| things like boiler plate easier.
|
| I'm not saying it's easy to implement. Rather the ideas
| are there and implementable. Typescript has them and it's
| relatively young.
| lowmagnet wrote:
| It was due to the careful and deliberate nature of the Go
| team, and the backward compatibility guarantee. It took
| years for the group to put together a proposal with minimal
| changes to the runtime and core libraries, and this
| implementation in 1.18 will be limited in scope to only add
| the feature, waiting for future versions to update other
| core libraries to adapt generics in a backward-compatible
| way.
| Cthulhu_ wrote:
| Have you even looked at other languages' implementation of
| generics? Java's implementation takes up a significant part
| of the language spec, compiler, and VM for example.
|
| Here's an insightful comment from some time ago, explaining
| why it's a technical issue, not a political one:
| https://news.ycombinator.com/item?id=9622417 It links to
| this FAQ highlighting a LOT of the complexities and
| pitfalls of generics in Java, things that are all to easily
| overlooked by armchair language expert: http://www.angelika
| langer.com/GenericsFAQ/FAQSections/TypePa.... Note that
| that's just one chapter in a very large document.
|
| Comments like this say more about their author's arrogance
| than that of the Go language team.
| nauticacom wrote:
| To me, "takes up a significant part of the language spec,
| compiler, and VM" isn't a meaningful reason to exclude
| something from a language, unless it's a hobby project.
| The job of languages, imo, is to provide
| tools/features/syntax for expressing problems, whether
| their implementation is complex or not. Ruby is an
| incredible language to use, but its implementation is
| notoriously hairy. That internal complexity is not
| something that matters to me in the slightest.
|
| I understand the Go team's reluctance to get the _user-
| facing_ interface wrong, and end up with something like
| type-erasure in Java; that 's slightly connected with
| implementation complexity, but saying "it's complex to
| implement and specify" doesn't seem enough to me.
|
| [edit: made it clearer that this is my thought on the job
| of languages and not some universal truth]
| remus wrote:
| > It should be noted that "takes up a significant part of
| the language spec, compiler, and VM" isn't a meaningful
| reason to exclude something from a language, unless it's
| a hobby project.
|
| If we assume complexity ~= "takes up a significant part
| of the language spec, compiler, and VM" then I think it's
| an excellent reason not to include something! Somebody
| has to maintain this stuff and making it complicated
| makes that hard, which in turn means less time to spend
| on things like tooling, performance improvements and
| documentation which then makes our lives as users of the
| language harder.
|
| Of course there is a trade-off here but I think, in
| general, the go team manage to strike a nice balance.
| nauticacom wrote:
| Right, but the entire point of my comment was that "takes
| up a significant part of the language spec, compiler, and
| VM" is _not_ a good approximation of complexity. It can
| be related, but it is not necessarily true that something
| with a complex implementation has a complex interface.
| remus wrote:
| I think we are talking past each other a bit, as I
| completely agree with
|
| > it is not necessarily true that something with a
| complex implementation has a complex interface.
|
| In turn, my point is that as a language implementer you
| only have so much time available to work on the language
| and surrounding ecosystem. If your time is spent dealing
| with a complex spec, compiler and VM then you have less
| time to spend on the rest of the ecosystem. I think go
| has shown that spending tim on the surrounding ecosystem
| can be very valuable (e.g. go fmt, go vet and more
| recently go fuzz).
| nauticacom wrote:
| Ah, I understand now. That's a fair point! I agree that
| the excellent Go tooling is one of its strengths.
| assbuttbuttass wrote:
| I actually have a different view. One of the things I
| love about go is it's a simple language, and I can hold
| the whole language spec in my head while I'm programming.
|
| A generics implementation can't sacrifice the simplicity
| of the language, or make it any harder to read go code.
| cultofmetatron wrote:
| lisp and smalltalk both manage this while allowing
| sophisticated abstractions.
| nauticacom wrote:
| I can hold the whole language spec in my head while I'm
| programming
|
| People love to say this about Go, but it's not something
| that, like, _actually matters_ (and I doubt it 's
| literally true). A language can be reasonably
| understandable such that you can effectively and
| productively program in it without being aggressively
| simple. Again, to use the case of Ruby, I might not
| remember every single syntactical construct or handling
| of every edge case, but the language is reasonably
| understandable such that I can write programs without
| constantly asking "what was the syntax for that?" or "how
| do I express this?" As a counter-example, I think the
| complexity of C++ is not just limited to its
| implementation, and leaks out to its interface.
| ...sacrifice the simplicity of the language, or make it
| any harder to read go code
|
| These are two separate concerns which, while somewhat
| related, are not directly correlated. A simple language
| can make it more obvious which syntactical constructs are
| being used and what literal operations are being
| performed, but there are many more dimensions to reading
| code than just those.
| leshow wrote:
| I can hold the entire spec to brainfuck in my head, but
| it doesn't make it any easier to write.
| esprehn wrote:
| Which part of the JVM is complicated by generics? They're
| type erased so the VM shouldn't really care. The compiler
| on the other hand has plenty of complexity...
| FlyingSnake wrote:
| There are 2 kinds of languages, one that people love to talk
| about and philosophize about and others that are used in real
| projects. Golang firmly fits into the 2nd category of languages
| that are highly opinionated and full of pragmatic choices. It is
| rare for a language to capture so much mindshare within a decade
| of it's launch and I'm glad that Go had managed to reach this
| stage. I am really looking forward to what this new era of Golang
| brings with it.
| Shadonototra wrote:
| Exactly, just like firefox / chrome
|
| you hear about firefox everywhere, everyday, and yet only has
| 3% marketshare
| [deleted]
| Cthulhu_ wrote:
| I'd add to your first category that there's a lot of languages
| that adopt features that other languages have, making a ton of
| languages converge into basically the same language with some
| caveats. I don't remember the post now but I believe it was
| posted on HN some time ago, it was pretty insightful.
|
| Anyway yeah, I'm glad Go is resistant to change.
| rob74 wrote:
| No idea why you are getting downvoted, but I fully agree with
| that sentiment. There are already enough open source
| languages who seemingly want to be "everybody's darling" and
| implement any reasonably sensible feature request. One
| example: PHP's new "match" expression
| (https://www.php.net/manual/en/control-structures.match.php).
| Of course, I can understand that people like Go's more
| flexible "switch" better than the "traditional" C-style one,
| but if a language already has the traditional version, does
| it really have to add a new one which does mostly the same
| thing and in doing so cause headaches for thousands of
| developers who use classes or constants named "match"?
| jerf wrote:
| http://www.jerf.org/iri/post/2908 ?
|
| (BTW, 2011 on that. I would not _today_ agree with the
| statement "the Haskell community is the only community I
| know that is doing new things in the field of language and
| API design". I think Rust is doing interesting new things
| now. In 2011 they were still working on basic functionality.
| There's a couple of other interesting little up-and-coming
| languages.)
| pydry wrote:
| They resisted generics since day 1 on the basis of pragmatism.
| Now they included them on the basis of pragmatism?
|
| I remember something similar with their approach to package
| management which they said wasnt necessary for years.
|
| They really do seem to resist doing the right thing for as long
| as possible.
| hbn wrote:
| I believe I watched a talk from Rob Pike a few years ago
| where he mentioned that Go didn't have generics, not because
| they didn't want generics, but because they wanted a Go-like
| way of doing them, and wanted to spend a lot of time making
| sure they were done right.
|
| I'm paraphrasing and I wish I had a source for you but I'm
| pretty confident I didn't make that up.
| pydry wrote:
| The FAQ said something similar - not that they were
| vehemently opposed, just that it wasnt a priority.
| kortex wrote:
| They never resisted generics as a concept. But they refused
| to implement generics in a way which compromised other Go
| values. Compilation speed was a big one. It's easier to
| implement generics if you sacrifice compilation speed (see:
| c++, rust, and iirc java). To their credit, it took the
| community a looong time to figure out how pull that off,
| because it's a _hard problem_. But I think they 've done it.
| esprehn wrote:
| FWIW Java doesn't sacrifice compiler speed for generics,
| they're entirely erased at compile time which is cheap.
|
| What they sacrificed was runtime correctness, because the
| type erasure lets you sneak invalid types into unsuspecting
| code. How much of a problem that's caused in the real world
| is debatable.
| inglor wrote:
| Are you sure you are not mixing up runtime impact with
| compiler speed? In Java generics are still part of the
| type system and are type checked which is a non trivial
| part of the compile time increase in generics typically.
| adamrt wrote:
| It's not like they just had them ready to go at the flip of a
| switch and we're just holding out.
|
| There were trade offs and they didn't have a solution on day
| one.
|
| They've always said they were open to them with the right
| implementation.
| sacado2 wrote:
| They weren't ever firmly opposed to generics. Here's the FAQ
| from 2009:
|
| https://web.archive.org/web/20091113154906/http://golang.org.
| ..
|
| > Generics may well be added at some point. We don't feel an
| urgency for them, although we understand some programmers do.
|
| > Generics are convenient but they come at a cost in
| complexity in the type system and run-time. We haven't yet
| found a design that gives value proportionate to the
| complexity, although we continue to think about it.
|
| 12 years later, here they are.
| FlyingSnake wrote:
| Java was created in 1995 and got generics in JDK 1.5 in
| 2004, I don't see anyone using this argument against Java.
| The weird fixation people have about Golang generics is
| really tiresome, that too after they have added generics
| after much deliberation.
| masklinn wrote:
| > Java was created in 1995 and got generics in JDK 1.5 in
| 2004, I don't see anyone using this argument against
| Java.
|
| Java was created in an age where very few languages with
| mainstream relevance had userland generics.
|
| Go was not, and generics had already had to get (somewhat
| painfully) retrofitted in two of the above.
| DylanSp wrote:
| Yeah, this. In 1995, about the only mainstream language
| with generics was C++ with templates. (Same in 2000 when
| C# was released, incidentally)
|
| When Go came out in 2009, though, Java and C# had pushed
| generics into the mainstream. Additionally, they'd shown
| some of the problems with trying to retrofit generics
| onto a language and ecosystem that didn't previously
| support them.
| jerf wrote:
| Having watched this for a while, I would say, my fellow
| programmers, there's no need to build elaborate
| psychological defenses for why you don't want to use a
| language. Just don't use it. There's too many languages
| to know them all anyhow. You don't have to decide not to
| use something, then justify your decision with a few
| comfort blankets that you post every time the topic comes
| up. Just don't use it, and leave it at that. Or at the
| very least, skip posting your comfort blankets every time
| the topic comes up. There's a dozen languages I'd like to
| know better, and don't use them, and I don't run around
| giving myself "reasons" I don't learn them. The "reason"
| is simple: I don't have time. Languages are not an attack
| on you. Nobody who designed a language was even thinking
| about you when they created them.
|
| I speak here to those who slag on Go and haven't so much
| as run "Hello World" in it. Those who _have_ used it,
| especially for some period of time, and especially those
| who tried long enough to learn to program Go-in-Go (as
| opposed to Rust-in-Go or C++-in-Go, etc.), and decided
| they didn 't like it due to their experience, I invite to
| continue discussing. You're not who I'm talking about
| here. Real experiences with the language are valuable
| contributions.
|
| Those who haven't had real experiences are not making
| valuable contributions. "Lol generics, lol they realized
| they're wrong and I was right all along" and "Lol error
| handling is bad in Go" are not valuable contributions.
| kwertyoowiyop wrote:
| And of course this opinion is getting downvoted! :-)
| FlyingSnake wrote:
| This here is the right sentiment, thanks for saying this.
| I would not bother the internet if my preferred feature
| is not present in Zig/Nim/Elixir.
| corn_dog wrote:
| You don't think it contributed at least a little to Go
| eventually adding generics?
| jerf wrote:
| No, I don't think the whining did a thing. It may seem
| impressive on HN, but compared to the continuous stream
| of whining any successful project receives about all
| sorts of things I suspect it was weighing less heavily on
| their mind than HN would think, because it's
| proportionally much smaller than HN thinks. Also, it's
| not like Go isn't already fairly successful; if I wrote a
| language as successful as Go I wouldn't exactly be crying
| myself to sleep every night, you know?
|
| Cruise through the Go issues and look at all the closed
| issues. Then, for context, cruise through Rust's or
| Python's, or your favorite open source project of some
| size that isn't even a programming language. It's a
| constant deluge.
|
| What did it was real use cases from using the language
| for a long time, offered by serious people who weren't
| just berating the designers. If you read the generics
| design, and especially if you read the whole history of
| the design, you can see where this has had an impact,
| where the features are tuned for the use cases presented
| by the community, and how the design has changed at least
| twice in a major way (depending on how you count, of
| course) as people work through the use cases.
|
| You'll also come to understand better why it's not like
| you can just flip a switch and "turn on generics" and why
| everyone running around claiming it was easy is dead
| wrong. You can also learn some of this by paying
| attention to discussions of generics in other languages
| when Go is _not_ a topic, because it 'll become clear
| when _not_ discussing Go, there 's a lot of broken
| generics and strange edge cases and poor decisions made
| by existing languages that we have to live with forever.
| Not that _all_ of them are broken, but, again, the idea
| that some care needs to be taken wasn 't something the Go
| team just made up. There's plenty of languages, even big
| name languages like Java, that "flipped the switch and
| turned on generics" and it turned out not to be as
| awesome as presented, because it's a legitimately hard
| problem even in 2021.
| pjmlp wrote:
| In 1995, Standard ML, Ada and Eiffel had generics and
| were hardly mainstream, C++ templates were still
| experimental, everything else did not used them.
|
| A tad different from the computing world in 2009.
| neilalexander wrote:
| Is it really that much of a bad thing to iterate based on
| real world experience?
| [deleted]
| maleldil wrote:
| It is when they spend a decade insisting that they right
| and everyone else was wrong, then ended up doing it anyway.
|
| Generics aren't a cutting edge feature that they wanted to
| see how it would develop. Their objection against it was
| ideological.
| neilalexander wrote:
| I don't really understand this type of criticism. People
| complained that Go didn't have generics, and now that
| they've delivered, people still want to complain for some
| reason.
|
| I can quite believe that the Go team wanted to be sure
| that the approach made sense for Go, that it was the
| right solution to the right problem and to keep to their
| backward compatibility promise. Experience is a good
| teacher. I really don't know why it matters in the
| slightest that they didn't arrive at that on day one.
| philosopher1234 wrote:
| Why are you so bitter about it?
| mseepgood wrote:
| No, they didn't.
| ianpurton wrote:
| It's not enough.
|
| As a rust guy I get way more features in the language that help
| me write error free software.
| Cthulhu_ wrote:
| Nobody is pushing you to use Go. Nobody is telling you Rust is
| bad. There is no language war. It's not an either/or. Stick
| with Rust if you're happy with it, nobody is attacking you over
| it.
| 1_player wrote:
| Go write Rust then, what's the problem?
| mfrw wrote:
| As person who uses both Rust & Go at my $DAYJOB, I would say,
| both have their merits and demerits, I think, we should view
| them as tools instead of attaching ourselves to any particular
| language emotionally. I like to think them as different tools
| for different use-cases. Use the right tool for the right job.
| In my opinion, go does an excellent job at networking
| (TLS/HTTP) & quick cli apps while rust shreds text & does an
| amazing job at memory management (this is a figurative example;
| don't drone me if I missed your favorite feature).
| dmart wrote:
| I often see people recommend Go for CLI apps but I'm not sure
| why. The built-in `flag` package is really limiting. These
| days I mostly use Rust with `clap` which is the nicest flag-
| parsing experience I've found so far in any language.
| diegocg wrote:
| Go is a very opinionated language that lacks many features on
| purpose. If you want complex languages Go is definitely not a
| good choice.
| afr0ck wrote:
| So, for you, it won't be enough until Go (and possibly every
| other language that is different from Rust) is "rustified" and
| turned into a rust-like clone? ... just why?
|
| And BTW, Go is very safe! it has automatic memory management,
| and managed concurrency for writing bug-free concurrent code.
| usrbinbash wrote:
| The "lack" of "features" that are prevalent in other languages
| is a virtue of Go, not a flaw.
| 1_player wrote:
| Go with generics has definitely surpassed Python for me. Python
| is good for prototyping but the package management story and the
| "feel" of the language has ruined it for me. I used to love
| Python, until I used Django professionally, and the facade
| crumbled. I'm done with OOP and dynamic typing.
|
| Go felt good, a bit verbose, but my issue was that
| map/reduce/filter are a much better abstraction over imperative
| loops, and with generics, the dream of Go with more functional
| and high-level concepts is closer.
|
| This comment is going to be very controversial, so let me remind
| you this is my very own opinion.
| rirze wrote:
| fwiw, I think your experience speaks more to Djanjo and other
| OOP-inspired packages. Python allows for many different styles
| of packages to be written... and it's not always a good feature
| to have.
| Cthulhu_ wrote:
| Note that you still shouldn't use Go as a functional language
| (using map/reduce/filter); it's not optimized for functional
| programming, and the syntax would be pretty gnarly.
|
| A for-loop has what's called "mechanical sympathy", and will go
| through things in the order that it is in memory. It'll allow
| the compiler and runtime to manage things quickly through
| memory, CPU registers, and CPU pipelines.
|
| A great post on the subject is "Why Go Getting Generics Will
| Not Change Idiomatic Go": http://www.jerf.org/iri/post/2955
| lucian1900 wrote:
| The bit about "mechanical sympathy" is wrong, though. Plenty
| of languages inline map/reduce or iterator type code down to
| very efficient cache-friendly traversal of memory, most
| notably Rust.
|
| Go's compiler is just particularly naive.
| fsdjkflsjfsoij wrote:
| > Plenty of languages inline map/reduce or iterator type
| code down to very efficient cache-friendly traversal of
| memory
|
| Very few languages outside of Rust and Haskell actually do
| this reliably and that's including languages like Ocaml and
| F#. Rust and Haskell are certainly the only even remotely
| popular languages that do it.
| spekcular wrote:
| Does Haskell actually succeed here?
|
| This is perhaps not the right way to measure, but: When I
| last checked the programming language benchmark game [0],
| the Haskell submissions were basically as fast as
| C/C++/Rust. _But_ , this came at the cost of writing non-
| idiomatically/non-functionally - essentially abusing the
| language to write C in Haskell. I would be curious how
| well "idiomatic" Haskell compares to C++/Rust, in terms
| of the compiler optimizing away the functional
| abstractions.
|
| [0] https://benchmarksgame-
| team.pages.debian.net/benchmarksgame/...
| igouy wrote:
| The benchmarks game isn't limited to one Haskell program
| per task.
|
| Look at both
|
| https://benchmarksgame-
| team.pages.debian.net/benchmarksgame/...
|
| and
|
| https://benchmarksgame-
| team.pages.debian.net/benchmarksgame/...
| spekcular wrote:
| Thanks, that's pretty convincing.
| nine_k wrote:
| Does the elephant-in-the-room of C++ do it? I thought it
| does.
|
| I can't bet on what Java and JavaScript JITs make of map
| / forEach / filter / reduce, but I suspect that they can
| be pretty efficient, given the clear delineation and the
| repeated patterns.
| Zababa wrote:
| I think OCaml can do it with flamba, at least that's what
| this library readme says: https://github.com/c-cube/iter
|
| > with flambda under sufficiently strong optimization
| flags, such compositions of operators should be compiled
| to an actual loop with no overhead!
| kortex wrote:
| Actually I think while the _compiler_ is a bit naive, the
| _compiler writers_ are not. They are striving for
| simplicity, maintainability, speed, etc., vs trying to
| optimize high-level FP-esque idioms into fast machine code.
|
| The compiler has definitely gotten more optimal over the
| years, but it's a different beastie than the rust one.
| Because go is not rust.
| Zababa wrote:
| Speed and maintainability vs trying to optimize high-
| level FP-esque idioms into fast machine code is a false
| dichotomy. OCaml has a really fast compiler, it has been
| maintained by a small team for 25 years, and it produces
| fast machine code. A big caveat in comparing OCaml and Go
| would be multicore support, but it's coming in OCaml,
| without breaking existing programs and with only a few
| percent of performance lost.
| lucian1900 wrote:
| Go is not Rust, but there is a lot it could learn from
| Rust without sacrifice: sum types, Result for error
| handling, iterators with for loop support, [edit] non-
| nullable types etc.
| kortex wrote:
| I've wanted a Result type I could map over in Go as soon
| as I saw the idea. But someone recently pointed out,
| without pattern matching and early return, it's kind of
| nerfed. Not sure I totally agree (I think it'd still be
| awesome to have Result, if only for .map()), but I see
| their point.
|
| I disagree that it would be _without sacrifice_. That 's
| kind of the whole point.
|
| Unless I'm missing something, go has iterators with for
| loops.
| lucian1900 wrote:
| Go switches with exhaustion checks like in [1] would go a
| long way. An early return construct would be important as
| well, though, you're right.
|
| Go's for loops can only iterate over builtin types:
| slices, maps, channels, etc. You can't produce a custom
| type that is to be iterated over.
|
| 1. https://github.com/BurntSushi/go-sumtype
| sacado2 wrote:
| Not as simple as it seems. For instance, what is the zero
| value of a sum type? Let's say, the zero value of a
| Result<int, error>?
| Lev1a wrote:
| IIRC in Rust it has to be either of the Ok or Err
| variants and the enclosed type can then provide its own
| "zero value" via the standard library "Default" [0] trait
| or your own implementation for the particular type. That
| trait is also implemented not for "Result" but for
| "Option" giving it a default value of "None".
|
| [0]: https://doc.rust-
| lang.org/std/default/trait.Default.html
| sacado2 wrote:
| Yes, for Option the default value is quite obvious. I'm
| talking about Result, because it's the second best-known
| sum type, and it doesn't have an obvious default value.
| Lev1a wrote:
| Bindings in Rust have to initialized with an explicit
| value if the first use comes before the first
| modification/assignment otherwise [0] you get an error
| message with error E0381 [1]. Even if that explicit
| assignment is just through the use of the type's default
| method [2], if available.
|
| Since it's implemented for Option<T> you can do it the
| same way [3] for that, but that's not available for
| Result<T,U> since the semantics are different from Option
| which is basically just Rust's alternative for
| 'null'/'nil' (but verifiable by the compiler).
|
| Thus you'd have to _choose_ what variant of the enum you
| want to have at initialization, after which you can use
| the Default implementation of the enclosed type, if
| available (and so on, if there are more nested types).
|
| Though honestly I can't recall using the kind of pattern
| in Rust that would "need" something like that. Through
| the handling of code blocks as expressions, early returns
| etc. you for example don't need to initialize a variable
| before having an if-/match-/for-/while-/etc. block, you
| can simply use that block as an expression on the right
| side of the assignment [4].
|
| [0]: https://play.rust-
| lang.org/?version=stable&mode=debug&editio...
|
| [1]: https://doc.rust-lang.org/stable/error-
| index.html#E0381
|
| [2]: https://play.rust-
| lang.org/?version=stable&mode=debug&editio...
|
| [3]: https://play.rust-
| lang.org/?version=stable&mode=debug&editio...
|
| [4]: https://play.rust-
| lang.org/?version=stable&mode=debug&editio...
| [deleted]
| lucian1900 wrote:
| The zero value of a sum type can be the zero value of the
| first (or chosen) constituent. In this case, it could be
| Result<0>.
| sacado2 wrote:
| I'm not sure that would be any better, in practice, than
| doing return 0, nil.
| lucian1900 wrote:
| It would allow functions to be treated generically as
| returning error-able types. Since some functions even
| return 3 arguments where the third is the error, this
| isn't possible today.
|
| It would also allow defer-like syntax to be used on the
| value a function returns, to return early from the
| calling function. Rust's ? is an excellent example of
| this, allowing explicit delegation of error handling that
| is still very lightweight syntactically.
| kortex wrote:
| Function composition becomes a lot easier with
| Result/Option, because you can write functions in terms
| of assuming a "good" value (not nil/err or otherwise
| "bad") and then map over it. Or if we really wanna be
| fancy, flatmap/bind over it.
|
| Foo, err requires either that all receiving functions
| accept (foo, err), or manually nil-checking at every
| stage.
|
| Try/catch is the least composable, because deeper error
| types can "jump out" from any layer. Which means you have
| to keep wrapping catches, until you hit some base layer
| you can recover from. You get stack traces, but you lose
| type information along the way.
|
| Sum (result) and product (foo, nil) types preserve type
| information. Meaning you can operate more generically
| over it. Meaning less code duplication.
| kortex wrote:
| Perfect example of a caveat to "without sacrifice". For
| context, go really cares about having "zero values" -
| every initialized variable of some type must have a zero
| value.
|
| The zero of Error is nil, so logically this would be
| Result(0, nil). But what do you set the internal state?
| It's not Ok, cause that int isn't used, and it's not Err
| either.
|
| Option would work fine though and it would be amazing to
| map over options instead of nil checks.
|
| I think you'd need to build Result on top of Option, it's
| naturally kind of ternary - "I have value" "I have error"
| "idk", either internally or externally.
|
| What might be awesome would be if the Error were a slice
| type, nil would be "uninitialized" and empty slice means
| "initialized". still not...pleasant.
| DylanSp wrote:
| Zero values are definitely an issue, and it'd be hard to
| get rid of them while sticking to Go's
| imperative/statement-based style. Still, it'd nice to use
| an Option type instead of pointers.
| Sharlin wrote:
| It should be noted, though, that rustc does not really
| have any particular tricks up its sleeve to optimize
| functional patterns, or indeed much of anything. A lot of
| the LLVM IR that rustc generates is _astonishingly_ naive
| and verbose - largely by design! rustc totally depends on
| LLVM 's optimization passes to throw out all the
| boilerplate and output lean and mean optimized machine
| code.
| kortex wrote:
| Right but that just means it's LLVM being clever, not
| rustc.
|
| The main compiler is the self-hosting gc go compiler.
| Iirc ~~it's the reference implementation~~ erm I guess
| it's determined by spec, not reference implemenation. Gc
| is definitely "the default" though.
|
| Then There's the gofrontend, which is a compiler frontend
| to other compilers, which can work with gcc and llvm. I
| am not aware of the state of the art for these, but I
| wonder if there are performance differences.
| mananaysiempre wrote:
| (The key phrase is "stream fusion".)
| pierrebai wrote:
| That is a strange sentiment, based on the reasons you've given.
| Package management on Python with pipenv or poetry have not
| been an issue in my experience. The other half is kinda hard to
| pinpoint since "feel" doesn't say much, but is surprising given
| how clear and powerful the syntax is. I've also taken to use
| type annotation in Python to ease some of the typing
| obscurantism of pure dynamic typing.
|
| And python does have map / reduce and much more... so I'm not
| sure what you mean there.
|
| OTOH, I feel Go and Python are mostly used in quite different
| domains. To me, Python is the new bash. Go is more for those
| who dislike C++ and Rust (or Haskell or...) and prefer a
| certain kind of simplicity.
| throwaway894345 wrote:
| I like Python the language just fine. Static typing needs a
| good bit of work, but the real pain points for me have always
| been performance and tooling (especially package management).
|
| But Go has solid answers for these problems and an excellent
| static typing story (generics are gravy, but sum types would be
| nice). I've been very happy with Go on balance.
| metaltyphoon wrote:
| Expect when you need to use struct tags, then everything is
| flimsy. I would rather have C#'s attribute over strings only.
| deepsun wrote:
| > Package management
|
| Are you seriously saying that github.com/somelib is a better
| package management? Of course nobody forces to use that, but
| it's what actually been used in most go projects. Even NPM
| looks better in comparison.
|
| The best quality package management I've seen is Maven,
| followed by Cargo.
| hellcow wrote:
| Go has had built-in package management for a while now. It's
| extremely fast and generates reproducible builds effortlessly
| in its default behavior in a way I've not experienced before
| from any other tool.
| angryfeller wrote:
| npm is just another layer on top of git. go uses git
| directly. how is that any worse?
| cris-ward wrote:
| From someone who briefly used 'bower', which was JS
| dependency management using git, relying on git is a lot
| worse.
|
| Github repos can vanish, NPM will only let repos be deleted
| if they have no direct dependencies also on NPM. So you
| have some guarantees your dependencies wont vanish.
| saturn_vk wrote:
| If the repo was used at least once, it will be cached by
| the default proxy. At that point, deleting it will have
| no effect on builds
| ernst_klim wrote:
| Does go have some intermediate cache repository between
| github and enduser?
| uluyol wrote:
| Yes, https://proxy.golang.org/
|
| You can also configure go to use your own for internal
| projects or if you just want to avoid the global proxy.
| suddengunter wrote:
| I disagree
|
| for private Go packages all I need is to point it to another
| git repo. for nuget/maven etc - I need an artifact registry,
| with it's own bells and whistles
| mook wrote:
| As somebody currently working on something that has a mix of
| Node and Go, I definitely prefer github.com/somelib. In that
| case there's no worry about package name conflicts (everybody
| has equally terrible names), so you can always end up doing
| imports with reasonable names because only the last bit
| matters. With a single namespace, people can (and do) camp on
| the obvious names, and often they move on and replacement
| libraries have to have cute names.
|
| This doesn't mean people _will_ name their things sensibly of
| course. I've seen golang projects with packages named after
| gardening, meteorology, and aviation... and each is totally
| confusing when you're new to it, especially when the naming
| theme is completely unrelated to what the project actually
| does.
|
| Here maven would be acceptable (similar to go, there is a
| domain identifier embedded) whereas cargo (bare words)
| wouldn't be great.
| maccard wrote:
| I want to second this. With quick compile times, fat binaries
| and first class support for crosd compiling, go is suitable for
| pretty much everything python would be used for. My only use
| cases for python are as a replacement to bash for shell
| scripting.
| travisd wrote:
| Other people point out ML is a use case where Go isn't
| suitable. And I agree.
|
| But as someone who used to write a LOT of Python, Go has
| replaced it for anything service or business-logic oriented,
| and while I do very little data wrangling and machine
| learning, Julia would be my go to for that. Julia and Go are
| in, many ways, complementary opposites. If you need to use
| PyTorch/TensorFlow, okay, fine Python (I'm not going to
| seriously advocate for just wrapping it all in PyCall.jl
| unless it's just incidental usage), but Julia is a really
| strong language for this stuff nowadays.
| kortex wrote:
| Eh, not really in the data wrangling and machine learning
| space, at least not quite yet. It's not really amenable to
| writing libraries for numerical processing - it ends up being
| super tedious to write something like numpy (you have to
| implement for every data type, there's at least a dozen+) and
| nigh-impossible to write an API like pandas, because
| dataframes are just too dynamic. You _could_ do these things,
| but it 's just super unpleasant.
|
| I'm hoping generics makes it easier to write things like
| numpy, without doing `meao_u8`, `mean_u16` etc.
|
| + there's bool, int/uint8,16,32,64, float32/64,
| complex64/128, that's 13 right there, plus object, a bunch of
| extended sizes on some architectures, and c-alias types.
| pjmlp wrote:
| Sorry to break it to you, interfaces are OOP and trace back to
| Objective-C and Common Lisp Object System protocols or BETA
| patterns.
| 1_player wrote:
| I'm talking about Go vs Python, not about the origins of OOP.
| anyfactor wrote:
| If you don't like Django then you should really try out Flask.
| It is everything that is right which is wrong about Django and
| vice versa.
| kortex wrote:
| I love python, and I don't blame you. I can't stand the Django
| way of doing things. Everything is so opinionated, dynamic, and
| magical in the bad way. Pytest has a similar vibe and it drives
| me nuts. Not a fan of OOP, either, I much prefer immutable
| objects that are either pure data, or convenience methods that
| return a copy. No more setters, state mutation methods,
| setattr, unless it's deeply abstracted away.
|
| Nowadays I use Fastapi, pydantic, Result, and static typing
| everywhere. Protocol interfaces are great.
| gautamdivgi wrote:
| This!!! I've done a fair bit of python api development mostly
| for ML services. We used flask/gunicorn and I'm considering
| moving to fastapi. I'm sure Django is awesome for what it
| does well but python has a lot more options.
|
| Fwiw - I do dabble in Go. I've used it for some very targeted
| systems work where I don't have to install a python
| interpreter on the target machine and hacking some k8s
| operators. I really like Go - but the ML ecosystem is pretty
| heavily python.
| flippinburgers wrote:
| Never needed in my opinion but here we go...
| akmittal wrote:
| More than being able to use it I am happy others will stop making
| jokes about Go
| Debug_Overload wrote:
| >will stop making jokes about Go
|
| If you seriously think that's gonna happen, you haven't been to
| Go mockery stations on the interweb.
| tomjen3 wrote:
| There are languages people don't complain about and languages
| that people use.
|
| For me, Go is essentially pointless without generics and better
| error handling (I love that there are no exceptions, but since
| 99% of the code just return the error anyway, that needs to be
| the default path), but even with it, it is not much more than C
| with garbage collection, a few nice features and better syntax
| in some cases.
|
| So even if it got these problems solved well, I still don't
| really think I would be using it.
| dgellow wrote:
| No more complaining about lack of generics, yeah! But you will
| still have people complaining about error handling in every
| single discussion about Go
| throwaway894345 wrote:
| I guarantee we will still hear about how long it took them to
| add generics to the language and how the language is only
| popular because of "massive Google marketing campaigns" and
| how the language is "stuck in 1970" and so on for years to
| come. People who make silly criticisms aren't likely to be
| pacified, and I don't think generics will make people less
| upset that Go is eating into their language's marketshare.
| lowmagnet wrote:
| I've been using Go since maybe 1.4 and that's only 7 years
| ago. I started using it as my main language around 2016 or
| so. I knew people complained about generics and wanted them
| myself, but the ease of using this language have far
| outweighed any complaints I've ever had about generics or
| comma-error or comma-ok patterns that have evolved out of
| the core design.
|
| I would _love_ some of the proposals surrounding errors to
| move forward, of course. But I 'm OK with the current
| state, and will be happier with 1.18.
| latchkey wrote:
| My all time favorite.
| https://golang.org/doc/faq#closures_and_goroutines
| amelius wrote:
| This caveat exists in every language that supports
| closures, afaict.
| ameliaquining wrote:
| Java's solution to this problem is maybe the simplest and
| most elegant: The compiler simply won't let you reassign
| to a local variable after it's been closed over. I think
| Go erred by not doing this. (Although I guess it would
| have complicated things a little because Go has mutable
| value types, so you'd need to figure out how to handle
| those.)
| 5e92cb50239222b wrote:
| Some... _cough_ ... oxidized languages prevent you from
| doing stupid shit like that. But apparently those
| languages are too complicated, I'd rather not rely on
| compiler helping me and keep yet another rule in my head
| as I'm writing code.
| heheheheheeh wrote:
| Even if it didnt, I'm sure you'd be able to realize your
| mistake while you wait 6-8 weeks for you code to compile.
| roblabla wrote:
| Err, no? Most languages will make a copy for scalar
| values (e.g. ints), e.g. Javascript and python do that.
| C++ and Rust go further and provide the user the ability
| to take the arguments by value or reference, even for
| classes/structs, which gives you control over what you
| want. And in this specific case, `v` should be a new
| instance for each iteration really, it makes very little
| sense to say that a reference to v of a previous
| iteration of the loop stays alive for the next iteration.
| Which is why the program as it exists would be a compile
| time error in rust, for instance (Maybe in C++ as well,
| I'm not well-versed enough in the lambda rules of C++).
| jhgb wrote:
| What does this have to do with values or references? They
| are orthogonal to scopes, and this example is an issue of
| scoping. A closure finds free variables in one of its
| enclosing scopes. If the for loop creates one mutable
| binding for its control variable, even multiple closures
| created within the loop's body can all see this single
| mutable binding because they all share the single
| environment with this mutable binding in which all of
| them were created, so they can all observe this binding
| mutating over time. There are no "arguments by value or
| reference" because the closure in the example is nullary
| -- it has no arguments at all.
| ImprobableTruth wrote:
| They're talking about _capture_ by value or reference. If
| you use capture by value, created closures will use the
| value of captured variables at the time the closure is
| generated.
|
| e.g. in C++, where one has to make capture by reference
| explicit int i = 0; auto f = [x
| = i, &y = i] { //x captures i by value, y by reference
| std::cout << "Value:" << x << ", Reference:" << y;
| }; i++; f();
|
| will print out "Value: 0, Reference: 1".
| jhgb wrote:
| I'm not sure you can call this "a closure". That term has
| a rather specific meaning related to lexical scoping
| which simply doesn't deal with copies or references or
| anything of the kind. There's no "capture by value or
| reference" since it's not a copy of a value, or even a
| reference to it -- it's one and the same variable binding
| inside _and_ outside of the closure (whereas a reference
| would be another variable name referring to the same
| value, or at least a differently scoped variable of the
| same name referring to the same value, but that 's not
| lexical scoping anymore). To put it bluntly, C++ is
| faking closures, since without subjecting environments to
| GC or refcounting, it can't delete the shared
| environments at just the right time. They just jumped on
| the bandwagon of closures being fashionable nowadays and
| tried to emulate closures as closely as possible by
| constructing artificial automatically generated objects
| in the background using some syntactic sugar without
| breaking the existing language.
| ImprobableTruth wrote:
| I don't really understand your objection. How is
|
| >at least a differently scoped variable of the same name
| referring to the same value, but that's not lexical
| scoping anymore
|
| not lexical scoping? That's literally just how closures
| work under the hood.
|
| And that's exactly why closures have to deal with
| references (or copies) - every implementation of them is
| a function pointer and a record for the lexical
| environment, the latter of which requires that at closure
| creation time the relevant bindings are captured, either
| by creating a reference or making a copy.
|
| I also don't understand why C++'s (or Rust's) closures
| would be 'fake'. If you capture by reference, they work
| exactly like the closures of other languages. Not having
| a GC just means you have to be wary of lifetimes. If you
| use a reference counting pointer (/some other GC'd
| pointer) you _literally_ have the same closures as other
| languages.
| jhgb wrote:
| > How is ... not lexical scoping? That's literally just
| how closures work under the hood.
|
| In the presence of references in the language, these two
| cases may be observationally indistinguishable (maybe,
| I'm not a C++ guru?) but they're still different language
| features. Lexical scoping does not require taking a
| reference.
|
| > And that's exactly why closures have to deal with
| references (or copies)
|
| No, they don't. They deal with bindings. References are
| either an explicit thing you create (as in, int &b=a; or
| such), or a parameter passing mechanism...but a free
| variable is neither (it's not a parameter to the closure
| in any case), and it exists even in languages with no
| notion of references whatsoever, such as for example
| Scheme.
|
| > I also don't understand why C++'s (or Rust's) closures
| would be 'fake'. If you capture by reference, they work
| exactly like the closures of other languages. Not having
| a GC just means you have to be wary of lifetimes.
|
| Yeah, and that's at least one of the things that make it
| fake. Why would you have to be wary about lifetimes?
| Closures in languages that support them Just Work(TM).
| earthboundkid wrote:
| You are wrong about Python. It absolutely does the wrong
| thing: >>> funcs = [] >>> for i
| in range(10): ... def f(): ...
| print(i) ... funcs.append(f) ...
| >>> [f() for f in funcs] 9 9 9
| 9 9 9 9 9 9
| 9 [None, None, None, None, None, None, None,
| None, None, None]
| kortex wrote:
| String is a pointer/slice type under the hood, even if
| you don't see the asterisk. So when you are passing v,
| you are passing a reference to a slice which gets updated
| by the loop. Since the goroutines can run in parallel,
| you print whatever v is pointing to at the time.
|
| C++ lambdas do the same thing if you pass a pointer.
|
| Python would do the same thing if you had a mutable non-
| threadsafe objects passed to threads. Eg if you iterate
| over a list of dicts, and modify the dicts, you'll get
| the same effect.
|
| So then the question becomes, why does v get re-used,
| instead of assigning a new pointer each time? Dunno,
| probably performance. I could see the latter generating a
| lot of garbage, which can be totally avoided if you don't
| pass mutable references to goroutines.
|
| What go _really_ lacks IMHO is some kind of _const_
| modifier for these kind of references. Maybe it does, all
| I remember are const scalars.
| jhgb wrote:
| > String is a pointer/slice type under the hood, even if
| you don't see the asterisk. So when you are passing v,
| you are passing a reference to a slice which gets updated
| by the loop. Since the goroutines can run in parallel,
| you print whatever v is pointing to at the time.
|
| You'll have the same problem with a simple integer (for
| example, as in https://go.dev/play/p/uqvRoO3ynZt).
| Nothing to do with v being a reference to something.
| latchkey wrote:
| Ok then... how about something easier... for
| bar := range list { }
| Joker_vD wrote:
| And of course "list" is defined as []int, so you get
| _really_ peculiar results.
| rob74 wrote:
| People who are looking for reasons to complain will always
| find more than enough - in Go and any other language too...
| friedman23 wrote:
| We wont
| SPBS wrote:
| Wait til they find out that methods cannot introduce generic
| parameters. I predict that complaints will shift from 'no
| generics' to 'no generic methods'.
| rad_gruchalski wrote:
| Why does one get bothered with that argument anyway? If it
| works, it works. People who complain are the people who have a
| problem. But it's a different problem and they don't realise
| that.
| usrbinbash wrote:
| Agreed.
|
| There are only 2 kinds of languages: Those people complain
| about, and those nobody cares about.
___________________________________________________________________
(page generated 2021-12-15 23:02 UTC)