[HN Gopher] Good-bye core types; Hello Go as we know and love it
       ___________________________________________________________________
        
       Good-bye core types; Hello Go as we know and love it
        
       Author : ingve
       Score  : 177 points
       Date   : 2025-03-26 16:18 UTC (6 hours ago)
        
 (HTM) web link (go.dev)
 (TXT) w3m dump (go.dev)
        
       | kubb wrote:
       | Nice! For anyone wondering, Go 1.25 won't be adding any actual
       | language features. It's a minor release.
       | 
       | Maybe we get sum types by 1.30 :)
        
         | qaq wrote:
         | Honestly that's basically my last item on the go wish list :)
        
         | ashishb wrote:
         | I wish we can have immutable runtime objects (e.g. final in
         | Java or const in C++).
         | 
         | Go has constant (`const`) type that can be evaluated at
         | compile-time but no const type for something that can only be
         | evaluated at Run time.
        
           | blibble wrote:
           | final in java only makes the primitive (or reference)
           | immutable
           | 
           | not the object
        
             | ashishb wrote:
             | Class Rect { final int x, y;                 //Constructor
             | goes here
             | 
             | }
             | 
             | Rect r1 = new Rect(1,2);
             | 
             | Is this not sufficient to create an immutable rectangle
             | that I can pass around safely in a multi-threaded code?
        
               | maleldil wrote:
               | When x and y are primitives, yes. But if they're objects,
               | final only prevents you from re-assigning them. You could
               | still call methods that mutate them.
        
           | pie_flavor wrote:
           | Non-deeply-immutable reference fields are a joke and solve no
           | problems. They don't save you from needing to make defensive
           | copies to stop shared mutation, and everything else is a
           | padlock on your left pocket to stop your right hand reaching
           | in.
        
           | drdaeman wrote:
           | I'm afraid that'll only result in some people using those
           | inappropriately then other people using `reflect` to mutate
           | those objects. Just like with "private" methods and fields
           | when library authors create a good library but don't expose
           | something crucial for anther person's task at hand.
        
             | XorNot wrote:
             | Man I can't remember whichever black magic I invoked to
             | bust into some C# sealed classes for some office
             | application.
             | 
             | But I was glad it existed because it enabled a whole set of
             | valuable business automation at the time.
        
         | int_19h wrote:
         | All they need to do at this point is allow type union
         | interfaces to be used as regular types and not just generic
         | type constraints.
        
           | kubb wrote:
           | And modify the switch statement to be able to ensure that all
           | variants are handled.
        
             | carlmr wrote:
             | Exactly, since messing around with OCaml/F#/Rust I feel
             | like sum-types + exhaustive match (with deconstruction) is
             | such a powerful construct to prevent logic errors and
             | ensure maintainability, that every language without it
             | feels so limited.
        
         | greenavocado wrote:
         | Go doesn't have direct sum types, but we can use interfaces and
         | type switches:                   package main
         | import "fmt"              // Define types for our "sum type"
         | type Success struct {             Value string         }
         | type Error struct {             Message string         }
         | // Interface for our sum type         type Result interface {
         | isResult()         }              // Implement the interface
         | func (s Success) isResult() {}         func (e Error)
         | isResult() {}              // Pattern matching using type
         | switch         func handleResult(r Result) string {
         | switch v := r.(type) {             case Success:
         | return fmt.Sprintf("Success: %s", v.Value)             case
         | Error:                 return fmt.Sprintf("Error: %s",
         | v.Message)             default:                 // Go requires
         | a default case, which can help catch new types
         | panic("Unhandled result type")             }         }
         | func main() {             result := Success{Value: "Operation
         | completed"}             fmt.Println(handleResult(result))
         | }
         | 
         | Here is a practical example of it:                   package
         | main              import (             "fmt"             "time"
         | )              // Common interface for our "sum type"
         | type Notification interface {             Send() string
         | isNotification() // marker method         }              //
         | Email notification         type EmailNotification struct {
         | To      string             Subject string             Body
         | string         }              func (n EmailNotification) Send()
         | string {             return fmt.Sprintf("Email sent to %s with
         | subject '%s'", n.To, n.Subject)         }              func
         | (EmailNotification) isNotification() {}              // SMS
         | notification         type SMSNotification struct {
         | PhoneNumber string             Message     string         }
         | func (n SMSNotification) Send() string {             return
         | fmt.Sprintf("SMS sent to %s", n.PhoneNumber)         }
         | func (SMSNotification) isNotification() {}              // Push
         | notification         type PushNotification struct {
         | DeviceToken string             Title       string
         | Message     string             ExpiresAt   time.Time         }
         | func (n PushNotification) Send() string {             return
         | fmt.Sprintf("Push notification sent to device %s",
         | n.DeviceToken)         }              func (PushNotification)
         | isNotification() {}              // Function that handles
         | different notification types         func
         | ProcessNotification(notification Notification) {             //
         | Type switch for pattern matching             switch n :=
         | notification.(type) {             case EmailNotification:
         | fmt.Printf("Processing Email: %s\n", n.Send())
         | fmt.Printf("Email details - To: %s, Subject: %s\n", n.To,
         | n.Subject)                          case SMSNotification:
         | fmt.Printf("Processing SMS: %s\n", n.Send())
         | fmt.Printf("SMS length: %d characters\n", len(n.Message))
         | case PushNotification:                 fmt.Printf("Processing
         | Push: %s\n", n.Send())                 timeToExpiry :=
         | time.Until(n.ExpiresAt)                 fmt.Printf("Push
         | expires in: %v\n", timeToExpiry)
         | default:                 // This catches any future
         | notification types that we haven't handled
         | fmt.Println("Unknown notification type")             }
         | }              // Function to record notifications in different
         | ways based on type         func LogNotification(notification
         | Notification) string {             timestamp :=
         | time.Now().Format(time.RFC3339)                          switch
         | n := notification.(type) {             case EmailNotification:
         | return fmt.Sprintf("[%s] EMAIL: To=%s Subject=%s",
         | timestamp, n.To, n.Subject)                          case
         | SMSNotification:                 return fmt.Sprintf("[%s] SMS:
         | To=%s",                                  timestamp,
         | n.PhoneNumber)                          case PushNotification:
         | return fmt.Sprintf("[%s] PUSH: Device=%s Title=%s
         | ExpiresAt=%s",                                  timestamp,
         | n.DeviceToken, n.Title, n.ExpiresAt.Format(time.RFC3339))
         | default:                 return fmt.Sprintf("[%s] UNKNOWN
         | notification type", timestamp)             }         }
         | func main() {             // Create different notification
         | types             email := EmailNotification{
         | To:      "user@example.com",                 Subject:
         | "Important Update",                 Body:    "Hello, this is an
         | important update about your account.",             }
         | sms := SMSNotification{                 PhoneNumber:
         | "+1234567890",                 Message:     "Your verification
         | code is 123456",             }                          push :=
         | PushNotification{                 DeviceToken: "device-token-
         | abc123",                 Title:       "New Message",
         | Message:     "You have a new message from a friend",
         | ExpiresAt:   time.Now().Add(24 * time.Hour),             }
         | // Process notifications             fmt.Println("===
         | Processing Notifications ===")
         | ProcessNotification(email)             fmt.Println()
         | ProcessNotification(sms)             fmt.Println()
         | ProcessNotification(push)                          // Log
         | notifications             fmt.Println("\n=== Logging
         | Notifications ===")
         | fmt.Println(LogNotification(email))
         | fmt.Println(LogNotification(sms))
         | fmt.Println(LogNotification(push))                          //
         | We can also store different notification types in a slice
         | notifications := []Notification{email, sms, push}
         | fmt.Println("\n=== Processing Notification Queue ===")
         | for i, notification := range notifications {
         | fmt.Printf("Item %d: %s\n", i+1, LogNotification(notification))
         | }         }
         | 
         | The marker method pattern isNotification() prevents other types
         | that happen to have a Send() method from being considered
         | notifications. T
        
           | jimbokun wrote:
           | A bit cumbersome, but a nice workaround all the same!
        
           | flakes wrote:
           | The problem I have here, is that by being an interface you've
           | suddenly made the type nilable. This leads to nasty bugs and
           | segfaults, especially where nil is the default construct for
           | all interfaces.
           | 
           | Ideally sum types would be concrete/non-nilable somehow.
        
             | greenavocado wrote:
             | The workaround is even more cancerous but you could wrap it
             | in a struct:                   type NotificationWrapper
             | struct {             // This field holds the actual
             | notification data             Value interface{}         }
             | 
             | And use it like:                   func
             | NewPushNotification(token, title, message string, expires
             | time.Time) NotificationWrapper {             return
             | NotificationWrapper{                 Value:
             | PushNotification{                     DeviceToken: token,
             | Title:       title,                     Message:
             | message,                     ExpiresAt:   expires,
             | },             }         }
             | 
             | And destructure it with something like
             | func ProcessNotification(notification NotificationWrapper)
             | string {             switch n := notification.Value.(type)
             | {
             | 
             | Roll it all up in a nice syntax with a preprocessor haha
        
         | ajb wrote:
         | There's a proposal[1] by Ian Lance Taylor of the go team, but
         | it includes every sum type implicitly including nil. Which very
         | much not what you'd expect of a sum type, but every interface
         | being zeroable seems to be embedded quite deeply in the
         | language.
         | 
         | [1]https://github.com/golang/go/issues/57644
        
           | thiht wrote:
           | Every proposal they make start with something absurd, gets
           | backslash in the comment, and after a few iterations it ends
           | up with a lovely proposal. I almost suspect they do it on
           | purpose to make sure each significant proposal gets enough
           | engagement
        
         | karmakaze wrote:
         | For some reason, sum types is something that rarely gets done
         | right.
         | 
         | Most languages settle for something close and users defend
         | their choice/Stockholm syndrome.
        
       | giancarlostoro wrote:
       | I have been following Go since before it even had a Windows
       | build. I love that everything I learned back in 2011 when I
       | finally started experimenting with it, still applies. I never got
       | the opportunity to work with it, so most of my efforts with Go
       | have been small one off projects to learn it.
       | 
       | Only thing that bothered me was hearing an interview with the Go
       | devs where one of the key devs sounded like Generics would never
       | make its way into Go and it put me off the way he seemed so
       | adamantly against such a feature, but now that generics are in I
       | might start doing some of my side projects with Go moving forward
       | just to force myself to become more familiar with Go.
        
         | BugsJustFindMe wrote:
         | > _Only thing that bothered me was hearing an interview with
         | the Go devs where one of the key devs sounded like Generics
         | would never make its way into Go and it put me off the way he
         | seemed so adamantly against such a feature_
         | 
         | Everything about the development trajectory of Go so far
         | indicates that What Is Right And Good at any given moment is
         | largely determined by whatever makes building the compiler
         | easier and not what makes the lives of external developers
         | easier, until the external developers get loud enough about how
         | the language is failing to learn from the mistakes of the past
         | that the internal team relents with an "ok, ok, you win, our
         | bad".
         | 
         | And if I never see another apologist refrain of "You don't need
         | <x>. Just use this code generator to flood your repo with
         | thousands of lines of project-specific-for-no-good-reason
         | boilerplate" again it will be too soon.
        
           | maccard wrote:
           | Code generation has a time and a place, but that time and
           | place isn't replacing missing language features.
        
             | XorNot wrote:
             | I really wish proper enum types would be added. You always
             | codegen them, but it's the same code everytime.
        
               | therein wrote:
               | Same. People go around listing relatively controversial
               | improvements but I think we can all agree on this one. It
               | is the one that'd make my life easier the most when it
               | comes to day to day stuff.
        
           | throwaway894345 wrote:
           | I think most Go devs have been pretty happy with Go's
           | trajectory. I think it's mostly the people who aren't using
           | Go and are unlikely to start using Go no matter its feature
           | set who are the ones who are mostly ignored. It has also been
           | a really good thing that Go "doesn't learn from the
           | 'mistakes' of the past" or else it would have exceptions and
           | monads and lifetimes and inheritance and a Haskell-like
           | syntax.
           | 
           | Go isn't perfect, but it's wildly more productive in my
           | experience than any other language, and that matters a lot
           | more to me than being able to be maximally expressive or
           | abstract.
        
           | dimgl wrote:
           | Have you ever used Golang? I have not needed to use codegen
           | once.
        
         | MisterTea wrote:
         | The creators came from Bell Labs and are known to be pragmatic
         | where needed as well as deeply think about a problem and how to
         | solve it correctly. Languages are foundational so getting
         | things right the first time is critical to building a stable
         | ecosystem. Honestly, I am glad they pushed back against the
         | constant demands and gave themselves time to think about the
         | problem.
        
           | pas wrote:
           | Go is definitely a step up from C (and from C++ in many
           | important ways), but maybe they could have spent a tiny bit
           | more of that deep thinking about the problem of error
           | handling, so they would have come up with something better
           | than `if err != nil {}` ... no? Just me? Hm, okay.
        
             | bee_rider wrote:
             | To be fair, though, error handling is terrible in every
             | language, independent of how much the designers think about
             | it.
        
               | XorNot wrote:
               | Seriously. For the amount people glaze Rust on HN, error
               | handling when you actually try to use Rust is overtly
               | discussed as "oh yeah it's completely broken, most people
               | try to replace the whole thing..."
        
               | kibwen wrote:
               | Let's not flirt with false equivalences. I've seen
               | languages that do error handling worse than Go. I've also
               | seen languages that do better.
        
             | MisterTea wrote:
             | > `if err != nil {}`
             | 
             | What would you like instead?
        
               | Dylan16807 wrote:
               | The most basic thing would be a compact way to say "do
               | this call, if there is an error return it, otherwise give
               | me the value"
        
               | 9rx wrote:
               | That would be the most basic thing, but you'd never be
               | able to use it (toy code written for an internet comment
               | aside).
               | 
               | 1. Errors quickly lose their usefulness if you simply
               | pass them up the stack. Even just on the surface, if you
               | don't even know where the error came from, good luck
               | making sense of it. Other languages have tried to avoid
               | that problem by having things like "sidecar" handlers
               | that can handle the error elsewhere, but in the end
               | that's just moving code around. You haven't actually
               | solved the overhead of needing to do something with the
               | error.
               | 
               | 2. Errors simply passed up the stack are, more often than
               | not, going to leak implementation details. Consider a
               | function that fetches data from a SQL database, where the
               | underlying operations produce a "SQLNoResults" error. If
               | you let that flow through, callers are going to start to
               | rely on it. Now, imagine new requirements dictate that
               | you need to fetch the data from an HTTP service instead.
               | If you continue to simply pass the error along, now
               | callers are going to get a "HTTPNotFound" error instead,
               | breaking their usage. Not a good situation.
        
               | Dylan16807 wrote:
               | 1. It's not just moving things around. Often you want a
               | segment of code to all do the same thing on error.
               | 
               | 2. There are places where you want to abstract your
               | errors, but those places are not every function call or
               | even most function calls.
        
               | dharmab wrote:
               | I would have preferred a Result type.
        
             | burnished wrote:
             | Your IDE may/could collapse those blocks and also allow you
             | to write them from templates. That resolves most peoples
             | problems with error handling since it elides the ergonomics
        
             | 9rx wrote:
             | _> but maybe they could have spent a tiny bit more of that
             | deep thinking about the problem of error handling_
             | 
             | First, to understand how to handle errors differently, you
             | have to understand how errors are different.
             | 
             | Like, is a person's age an error? Your gut reaction is
             | almost certainly _" What? No. A person's age isn't an
             | error."_ Yet soon enough you're writing age verification
             | checks like: if age < 18 { /* not an adult */ }. if age <
             | 21 { /* not old enough to drink in the USA */ } - with all
             | the exact same problems if err != nil {} has. Clearly _it
             | is_ an error in certain contexts.
             | 
             | Keep going and you start to wonder what branching situation
             | isn't error handling. So, really, it seems to me what we
             | really want is a better way to express branching
             | operations. "if" is one of the earliest additions to
             | programming languages, so it stands to reason that it is
             | getting a little long in the tooth.
             | 
             | The effort to improve error handling is clearly there. Core
             | team member Ian Lance Taylor submitted a new proposal and
             | built a reference implementation just within the last few
             | months. There have been ~200 error handling proposals! It
             | is a super hard problem, though. A "tiny bit more" thinking
             | is not sufficient.
        
           | umanwizard wrote:
           | And yet, they still somehow ended up with one of the most
           | difficult-to-use modern languages.
        
         | geodel wrote:
         | My thinking is you are better off without Go. There is no way
         | to stop Go devs from saying something again you may not like
         | and at that point your effort in using Go would be a waste.
        
           | mappu wrote:
           | Is any language immune from that?
        
       | 762236 wrote:
       | Now that gen AI can help write code, is a garbage collector
       | necessary anymore?
        
         | logicchains wrote:
         | Manual memory management is one of the hardest things for LLMs
         | to get right.
        
           | hyperhello wrote:
           | What do LLMs "get right"?
        
             | gadflyinyoureye wrote:
             | Flutter widget design.
        
             | cratermoon wrote:
             | Whatever code examples got the most votes on StackOverflow.
        
             | rustc wrote:
             | LeetCode questions. They often give the memorized LeetCode
             | answer even if you slightly modify a question so it has a
             | different correct answer.
        
               | echelon wrote:
               | Lovable, V0, etc. generate landing sites with slick
               | design and easy editability. Startups are going to have
               | such an easy time of product demo and marketing sites.
               | 
               | React is quickly falling to LLMs.
               | 
               | Rust, in my personal experience, not so much.
        
             | eknkc wrote:
             | I seem to use them more and more for repetitive tasks.
             | Where I can write one line and will need to handle a couple
             | more in a similar manner. They work fine.
             | 
             | Also for refactoring they seem to do ok. Things like change
             | this to a function, extract this type etc.
             | 
             | They excel in snippets like "get unique items in this
             | array" or "sort this by property x" kind of stuff where you
             | could easily write or find an answer.
             | 
             | Oh I also like to use them for code review. Not that I'd
             | blindly trust one but you can have another eye to look at
             | your pr (i use claude code for this and love it) and see if
             | you introduced any side effects or missed something.
             | 
             | For anything more complex like having one write some
             | feature from scratch... meh. I haven't had much luck. Also
             | they seem to fuck up royally in a little complex project if
             | you do not isolate your request like I mentioned above.
        
         | jandrese wrote:
         | I'd say it is more necessary than ever given how quickly AIs
         | tend to forget what they've previously written once you get
         | past homework length use cases.
        
         | sunrunner wrote:
         | Sadly, the garbage collector is still needed to deal with the
         | output of the garbage generator ;)
        
           | hnlmorg wrote:
           | Thats beautifully put.
           | 
           | I'm almost tempted to print it out and frame it.
        
         | adhamsalama wrote:
         | Yes.
        
         | LPisGood wrote:
         | I'm curious what you mean by that.
         | 
         | Do you mean that AI can help write perfectly memory safe code
         | and so new languages shouldn't have a garbage collector?
        
         | meindnoch wrote:
         | Given the amount of garbage people are producing with LLMs,
         | garbage collectors are more necessary than ever.
        
         | timewizard wrote:
         | A garbage collector was never "necessary." Automated theft of
         | other peoples copyrighted code is not relevant to this fact.
        
       | liampulles wrote:
       | I love and continue to love how seriously the Go team takes
       | breaking spec changes, as well as spec changes in general.
       | 
       | Go generics are a bit of a blip in this to be honest, A) because
       | it is a big change, and B) because it can be difficult to use
       | (generic functions defined on types cannot use generic parameters
       | that aren't defined on that type, for example).
       | 
       | But in a way, I also think the constraints help avoid the overuse
       | of generics. I have seen Java and Typescript projects where
       | developers had way too much fun playing around with the type
       | system, and the resulting code is actually quite unclear.
       | 
       | In conclusion, I pray the Go team strive to and continue to be
       | conservative with the language.
        
         | VirusNewbie wrote:
         | >generic functions defined on types cannot use generic
         | parameters that aren't defined on that type, for example
         | 
         | This is bonkers to me, why???
        
           | zeeboo wrote:
           | https://go.dev/doc/faq#generic_methods
        
             | singron wrote:
             | This is a good write-up of the issue. To see where this
             | craziness could have led, see the C++ overload resolution
             | logic, which isn't the exact same problem but does smell
             | the same: https://en.cppreference.com/w/cpp/language/overlo
             | ad_resoluti...
        
           | maleldil wrote:
           | Because they chose a half-assed way to implement generics,
           | and the path they took doesn't interact well with the rest of
           | the type system.
        
       | vessenes wrote:
       | You could think of the Go dev team's last ten years as trying to
       | find the right balance between features (asked for by the expert
       | devs that use Go) and simplicity (a value that the designers
       | hold, but that most expert devs making feature requests don't
       | care about). Generics always felt to me like this dynamic in a
       | nutshell. Lots of good reasons to prefer generics when you need
       | them, and it feels like a nearly ecosystem-killing amount of
       | complexity to implement a type system like Rust on top of Go -
       | there's literally almost no reason to use Go in that case.
       | 
       | Anyway, I like seeing this slight reversion in favor of
       | simplicity, I think it's the right call for where Go's targeted:
       | being a better Java for teams of mid-tier engineers.
        
         | maccard wrote:
         | > there's literally almost no reason to use Go in that case.
         | 
         | I work in C# and C++ day to day now, and in $PREV_JOB I used Go
         | and C++. my go builds on a similar size project were quicker
         | than the linter in my C# project is right now. Go's killer
         | feature IMO is that it's _almost_ scripting level iteration
         | speed.
        
           | vessenes wrote:
           | I too like this feature of go quite a lot. But I think it's
           | supercharged by the major reason I'd pick go for a mid-size
           | team; the language is exceedingly easy to parse, code in and
           | understand even if you're not a genius. I think the testing
           | support and very moderate type support hit a valuable place
           | in development ecosystems -- as you say, you get near instant
           | linting feedback about a lot, and it's also pretty easy to
           | read and write in.
           | 
           | Basically, the mental model required for coding in go is low
           | load. That's a great feature.
        
           | parliament32 wrote:
           | Do real organizations actually use C#? Every time we've
           | evaluated it we concluded it's a worse, MS-flavor Java
           | rewrite so we didn't take it too seriously. Does it have any
           | actual advantages over Java?
        
             | pjc50 wrote:
             | It is IMO better than Java these days, although they're
             | pretty close. Whenever I have to go back to Java I find odd
             | things missing, like unsigned long.
             | 
             | AOT is pretty good when it works.
        
             | CharlieDigital wrote:
             | Lots of real orgs use C#.
             | 
             | StackOverflow survey (self reported) for 2024 shows it at
             | #5 leaving out HTML/CSS, and SQL[0]
             | 
             | DevJobsScanner shows it at #4 via scraping job postings[1]
             | 
             | It definitely has heavy adoption; well above Rust and Go
             | despite what we see here on HN.                   > Does it
             | have any actual advantages over Java?
             | 
             | The language evolves faster and is more akin to Kotlin than
             | to Java, IMO. The DX is fantastic and there are a few gems
             | like LINQ, Entity Framework, and Roslyn source generators.
             | Modern C# can be very dense yet still highly legible.
             | 
             | C# switch expressions with pattern matching (not switch-
             | case), for example[2], are fantastic.
             | 
             | [0] https://survey.stackoverflow.co/2024/technology
             | 
             | [1] https://www.devjobsscanner.com/blog/top-8-most-
             | demanded-prog...
             | 
             | [2] https://timdeschryver.dev/blog/pattern-matching-
             | examples-in-...
        
             | wseqyrku wrote:
             | > Do real organizations actually use C#?
             | 
             | Sure. For me the best thing about dotnet is that you most
             | likely find an official solution to most "basic" things
             | needed to develop microservices (I intentionally call these
             | basic because you don't want to worry about lots of things
             | at this level). Go on the other hand excels at cross-cut
             | and platform development.
        
             | osigurdson wrote:
             | >> Does it have any actual advantages over Java?
             | 
             | Probably not. Why learn C# if you already know Java?
             | Similarly, why learn Java if you already know C#?
        
         | LtWorf wrote:
         | I can't trust any programming language where there's data
         | structures I can't implement myself.
        
           | jimbokun wrote:
           | Generics really reduced the sets of data structures you can't
           | implement yourself by a lot.
        
             | divan wrote:
             | What data structures can't be implemented without generics?
        
               | bsaul wrote:
               | i guess maps and array ? ( if you wanted to reimplement
               | your own in a typesafe way, that is)
        
           | vessenes wrote:
           | You are not the target market for go then. I personally think
           | using Forth is fun, but not for large projects.
        
           | fuzztester wrote:
           | examples?
        
             | wwarner wrote:
             | anything you can 'range' over :)
        
               | dharmab wrote:
               | I have written my own types that can do this?
               | 
               | EDIT: Had to check, yeah I had to implement the iter.Seq
               | type to do it
        
               | umanwizard wrote:
               | Go added support for custom iterators a few versions ago.
        
               | hnlmorg wrote:
               | That's been possible for a couple of releases now
               | 
               | In fact I created a struct that you can range over just a
               | couple of days ago.
               | 
               | I can't say I love the way Go implemented it though. But
               | it does work.
        
         | devuo wrote:
         | It's interesting how simplicity so often gets mistaken for a
         | lack of sophistication. Designing a language for clarity and
         | maintainability is a laudable goal, and so is choosing to use
         | one. Chasing complexity, or reaching for the latest trendy
         | language that lets you "express yourself" in ten different ways
         | to do the same thing, isn't what makes someone an S-tier
         | engineer. Simplicity isn't a concession. It's a hard
         | discipline.
        
           | dwattttt wrote:
           | In exactly the same way, complexity you don't understand the
           | purpose of is often disregarded as complexity for
           | complexities sake.
           | 
           | It's easy to get things simple and wrong, and hard to get
           | things simple and right. And sometimes complexity is there
           | for a good reason, but if you don't work hard to understand,
           | you'll fall into the "simple and wrong" camp often.
        
         | trentnix wrote:
         | _> being a better Java for teams of mid-tier engineers._
         | 
         | That cuts me right to the bone.
        
           | karmakaze wrote:
           | This explains why I lost interest in Go right after it got
           | generics and went back to Java (or Kotlin actually).
           | 
           | I do like to dabble in F# still.
        
       ___________________________________________________________________
       (page generated 2025-03-26 23:00 UTC)