Made with KolourPaint and screenshots from Kate (with the GitHub theme).

  • TootSweet@lemmy.world
    link
    fedilink
    English
    arrow-up
    5
    ·
    edit-2
    11 days ago

    The Go programming language documentation makes a big deal about how it “reads from left to right.” Like, if you were describing the program in English, the elements of the Go program go in the same order as they would in English.

    I say this as someone who likes Go as a language and writes more of it than any other language: I honestly don’t entirely follow. One example they give is how you specify a type that’s a “slice” (think “list” or “array” or whatever from other languages) of some other type. For instance a “slice of strings” would be written []string. The [] on the left means it’s a slice type. And string on the right specifies what it’s a slice of.

    But does it really make less sense to say “a string slice”?

    In Go, the type always comes after the variable name. A declaration might look like:

    var a string
    

    Similarly in function declarations:

    func bob(a string, b int, c float64) []string { ... }
    

    Anyway, I guess all that to say I don’t mind the Go style, but I don’t fully understand the point of it being the way it is, and wouldn’t mind if it was the other way around either.

    Edit: Oh, I might add that my brain will never use the term “a slice of bytes” for []byte. That will forever be “a byte slice” to me. I simply have no choice in the matter. Somehow my brain is much more ok with “a slice of strings”, though.

    • sph@lemmy.world
      link
      fedilink
      arrow-up
      2
      ·
      edit-2
      11 days ago

      Go’s syntax is vastly superior once you have more complicated signatures, then the left-to-right truly matters. For example a variable that contains a pointer to a function that takes a function and an int and returns another function (like a decorator).

      In C the order becomes very hard to understand and you really have to read the thing several times to understand the type of fp:

      int (*(*fp)(int (*)(int, int), int))(int, int)

      In Go, you can just read from left to right and you can easily understand what f’s type is:

      f func(func(int,int) int, int) func(int, int) int

      It’s just much more readable.

      See: https://go.dev/blog/declaration-syntax

        • sph@lemmy.world
          link
          fedilink
          arrow-up
          3
          ·
          edit-2
          11 days ago

          This obviously just illustrates a point, but callbacks and decorators are not uncommon. And iterators are exactly like that:

          type (
          	Seq[V any]     func(yield func(V) bool)
          	Seq2[K, V any] func(yield func(K, V) bool)
          )
          

          Which is very readable.

          • phlegmy@sh.itjust.works
            link
            fedilink
            arrow-up
            3
            ·
            11 days ago

            Callbacks and decorators are fine, but callbacks/decorators to a function which itself takes a function pointer and returns another function pointer are crazy.

            I’ve thankfully never had to use recursive callbacks or decorators, but it seems like it could very quickly become difficult to keep track of.

            • sph@lemmy.world
              link
              fedilink
              arrow-up
              2
              ·
              edit-2
              11 days ago

              I don’t think it’s that uncommon. Let’s say you have a function that handles a request. A common use case is to add permission checks before applying that function. You can write a generic permission check a bit like this:

              func NeedsPermission(f func(Request) (Response, error), perm string) func(Request) (Response, error) {
                  return func(r Request) (Response, error) {
                      if !check(r, perm) {
                          return nil, NewPermError(perm)
                      }
                      return f(r)
                  }
              }
              
              // elsewhere
              Bar := NeedsPermission(Foo, "superman")
              

              This would allow you to separate the permission check logic from the business logic. Though to be fair, in Go they prefer to keep things as simple as possible but it’s just to illustrate that these concepts are not that alien.

        • ThirdConsul@lemmy.ml
          link
          fedilink
          arrow-up
          2
          ·
          11 days ago

          Wait until you learn about transducers (Are they in Go? If not natively, someone definitely ported them) and the abominations fp people code with them.