Hacker Newsnew | past | comments | ask | show | jobs | submit | tapirl's commentslogin

Yes, the sugar is just to make chain calls with parameter types possible. The sugar reflects the limitation of the basic of Go generics design. Now they would make the language even more complex for such a small need. In facts, there are more problems in Go generics need to be solved earlier than this: https://go101.org/generics/888-the-status-quo-of-go-custom-g...

Thanks for sharing. I had no idea Go's generics had this many limitations.

Go's generics design is the most clunky one among popular languages.

Exactly. We heard for years they wouldn't do generics it until they could do it right, and that was perfectly fine with me. Who wouldn't want a well thought out implementation? Then they released generics and it was like, "this is what you thought was the right way to do it?!"

What’s the approach they should have used instead and how would it be better? Especially in terms of keeping fast compile times and overall performance.

Are there any evidences which prove the process was done in a week?


> ..., comptime that is more powerful than Zig

It would be great if you can elaborate more here. I can't make the conclusion from Mojo's docs now.


Not OP, but see the entire section on metaprogramming: https://mojolang.org/nightly/docs/manual/metaprogramming/. Mojo's compile-time programming is influenced by Zig, but has features that are not in Zig e.g traits, generics (real generics), and constraints, that work together.


It might be feature richer, but it is hard to say it is more powerful. Sometimes, features (especially constraints) will reduce powerlessness.


That's fair, I think I should have just said "comparable to Zig". The type'd ness is what I was thinking of, but having actually written some zig in the last few days to play with their Io model / see what passing around an allocator is like, Zig is pretty fantastic.

I still prefer the structure in Mojo, but boy do I miss if/switch as expressions.


Well, it certainly allows you to encode invariants in a more precise manner.


It looks the following code will be rewritten badly, but no ways to avoid it? If this is true, maybe the blog article should mention this.

    package main
    
    //go:fix inline
    func handle() {
        recover()
    }
    
    func foo() {
        handle()
    }
    
    func main() {
        defer foo()
        panic("bye")
    }


recover()'s semantics make it so that "pointless" use like this can be inlined in a way that changes its semantics, but "correct" use remains unchanged.

Yes, maybe some code uses recover() to check if its being called as a panic handler, and perhaps `go fix` should add a check for this ("error: function to be inlined calls recover()"), but this isn't a particularly common footgun.


> ... and perhaps `go fix` should add a check for this (

This is an impossible task. For a library function, you can't know whether or not the function is defer called.

Maybe this is not an important problem. But it would be better if the blog article mentions this.


Great example, illustrating go1.26.1 go fix source inline transformation breaking program semantics. Raise it as a bug against go fix?


As I have mentioned, no ways to fix it. Because it is hard to know whether or not the handle function is called in a deferred call.


Thanks, that's a bug. We should never inline a function that directly calls recover. I've filed https://go.dev/issue/78193.


Or: your buggy code is no longer buggy.


You claim listens right for this specified example. :D

It is just a demo.


Another example (fixable):

    package main

    import "unsafe"

    //go:fix inline
    func foo[T any]() {
        var t T
        _ = 1 / unsafe.Sizeof(t)
    }

    func main() {
        foo[struct{}]()
    }
Go is a language full of details: https://go101.org/details-and-tips/101.html


another:

   package main

   type T = [8]byte
   var a T

   //go:fix inline
   func foo() T {
      return T{}
   }

   func main() {
      if foo() == a {
      }
   }
filed: https://github.com/golang/go/issues/78170 and https://github.com/golang/go/issues/78169


similar:

    package main

    //go:fix inline
    func foo[T [8]byte | [4]uint16]() {
        var v T
        var n byte = 1 << len(v) >> len(v)
        if n == 0 {
            println("T is [8]byte")
        } else {
            println("T is [4]uint16]")
        }
    }

    func main() {
        foo[[8]byte]()
    }



Go was my favorite language for a long time, and I have written many books and articles about it. However, since the release of Go 1.22 [1], that is no longer the case. Go 1.22 damaged Go's reputation for promoting explicitness and maintaining strong backward compatibility.

[1]: https://go101.org/blog/2024-03-01-for-loop-semantic-changes-...


for-loop variable capture was maybe the #1 worst decision in the language. It was never what you wanted. I appreciate Go's commitment to backwards-compatibility, but in this case breaking it was the right choice.


It is only right for for-each loops.

For 3-clause-for loops, if you have read https://go101.org/blog/2024-03-01-for-loop-semantic-changes-... carefully, it is hard to think it is right.


All the examples in that article are very exotic.

  for i, p := 0, (*int)(nil); p == nil; fmt.Println(p == &i) {
    p = &i
  }
Be honest, how many times have you actually seen code which depended on the address of a variable declared in a 3-clause for-loop remaining stable across loop iterations? Nobody does this. It's extremely weird and un-idiomaic. Heck, 3-clause for-loops are somewhat uncommon in and of themselves. Conversely, everyone who writes Go has experienced unintuitive capture issues with for-range loops.

Are you actually aware of any breakages this change has caused?


This one is just an example to demo one case of backward-capability breaking.

> All the examples in that article are very exotic.

Have you carefully read that article? All? You must be kidding. The article shows several cases used in practice.


this is a repeating pattern with languages; there's no commitment to design coherency, no governance, just a mad scamper to stuff features into the project until it becomes an absurd caricature of itself.

C++ did it so egregiously & disastrously you'd think language maintainers would have been scared straight. No, like moths to a flame, it is the preferred hill to die on.

This is how C99 keeps winning when it bleeping should not. It's settled science, however imperfect. It's not getting rearranged because someone read a blog post. It has stability in real-world clock-on-the-wall terms like nothing else.


The change made in Go 1.22 for 3-clause-for loops is not a new feature. It simply broke backward compatibility and old Go principles. It is much worse than C++'s stuff features.


What is your language of choice now then?


zig now.


This is one reason why I created TapirMD, which offers better specificity.


CSS sucks because it is sometimes elegantly simple and intuitive, other times a maze of quirky, frustrating hacks.


Similar to my "Go 101" books website, about 1000 line of Go code (started from 500 lines at 9 years ago). The whole website can be built into a single Go binary.


Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: