For the best experience on desktop, install the Chrome extension to track your reading on news.ycombinator.com
Hacker Newsnew | past | comments | ask | show | jobs | submit | history | tidwall's commentsregister

Looks to me like having the ability to write Go syntax and interop directly with C is the plus.

I do like Go's syntax but I can't help thinking the best language for C interop is C.

> I do like Go's syntax but I can't help thinking the best language for C interop is C.

SWIG[0] is a viable option for incorporating C code as well.

0 - https://swig.org/Doc4.4/Go.html#Go


I love how SWIG is still around! I first used it about 30 years ago to integrate with Perl, then later with Java.

>having the ability to write Go syntax and interop directly with C is the plus.

It's always a plus to interop with the lingua franca of programming languages.

I think D language approach is more organic and intuitive that you can interop directly, and now that it's natively supported by the D compiler make it even better [1],[2].

[1] Interfacing to C:

https://dlang.org/spec/interfaceToC.html

[2] Adding ANSI C11 C compiler to D so it can import and compile C files directly (105 comments)

https://news.ycombinator.com/item?id=27102584


if you're forgoing go features to get c interop anyway, why not just roll back to whatever go version gccgo supports at that point?

Go's syntax is basically C tho lol

what's the benefit? for loops?


"To keep things simple, there are no channels, goroutines, closures, or generics."

I wonder if it could be integrated with https://github.com/tidwall/neco, which has Go-like coroutines, channels, and synchronization methods.


I do this all the time. I’ll spend weeks or months on a project, with thousands of wip commits and various fragmented branches. When ready, I’ll squash it all into a single initial commit for public consumption.

This reminds me of a card swiping video game system I made years ago.

https://youtu.be/Z2xq3ns5Hsk

https://github.com/tidwall/RetroSwiper


Or this.

    func fetchUser(id int) (user User, err error) {
        resp, err := http.Get(fmt.Sprintf("https://api.example.com/users/%d", id))
        if err != nil {
            return user, err
        }
        defer resp.Body.Close()
        return user, json.NewDecoder(resp.Body).Decode(&user)
    }


I'm conflicted about the implicit named returns using this pattern in go. It's definitely tidier but I feel like the control flow is harder to follow: "I never defined `user` how can I return it?".

Also those variables are returned even if you don't explicitly return them, which feels a little unintuitive.


I haven't written any Go in many years (way before generics), but I'm shocked that something so implicit and magical is now valid Go syntax.

I didn't look up this syntax or its rules, so I'm just reading the code totally naively. Am I to understand that the `user` variable in the final return statement is not really being treated as a value, but as a reference? Because the second part of the return (json.NewDecoder(resp.Body).Decode(&user)) sure looks like it's going to change the value of `user`. My brain wants to think it's "too late" to set `user` to anything by then, because the value was already read out (because I'm assuming the tuple is being constructed by evaluating its arguments left-to-right, like I thought Go's spec enforced for function arg evaluation). I would think that the returned value would be: `(nil, return-value-of-Decode-call)`.

I'm obviously wrong, of course, but whereas I always found Go code to at least be fairly simple--albeit tedious--to read, I find this to be very unintuitive and fairly "magical" for Go's typical design sensibilities.

No real point, here. Just felt so surprised that I couldn't resist saying so...


> I would think that the returned value would be: `(nil, return-value-of-Decode-call)`.

`user` is typed as a struct, so it's always going to be a struct in the output, it can't be nil (it would have to be `*User`). And Decoder.Decode mutates the parameter in place. Named return values essentially create locals for you. And since the function does not use naked returns, it's essentially saving space (and adding some documentation in some cases though here the value is nil) for this:

    func fetchUser(id int) (User, error) {
        var user User
        var err Error

        resp, err := http.Get(fmt.Sprintf("https://api.example.com/users/%d", id))
        if err != nil {
            return user, err
        }
        defer resp.Body.Close()
        return user, json.NewDecoder(resp.Body).Decode(&user)
    }
https://godbolt.org/z/8Yv49Yvr5

However Go's named return values are definitely weird and spooky:

    func foo() (i int) {
     defer func() {
      i = 2
     }()
     return 1
    }
returns 2, not 1.


yeah, not really an expert but my understanding is that naming the return struct automatically allocates the object and places it into the scope.

I think that for the user example it works because the NewDecoder is operating on the same memory allocation in the struct.

I like the idea of having named returns, since it's common to return many items as a tuple in go functions, and think it's clearer to have those named than leaving it to the user, especially if it's returning many of the same primitive type like ints/floats:

``` type IItem interface { Inventory(id int) (price float64, quantity int, err error) } ```

compared to

``` type IItem interface { Inventory(id int) (float64, int, error) } ```

but feel like the memory allocation and control flow implications make it hard to reason about at a glance for non-trivial functions.


> My brain wants to think it's "too late" to set `user` to anything by then, because the value was already read out

It doesn’t set `user`, it returns the User passed to the function.

Computing the second return value modifies that value.

Looks weird indeed, but conceptually, both values get computed before they are returned.


> I feel like the control flow is harder to follow: "I never defined `user` how can I return it?

You defined user in the function signature. Once you know you can do that, there is nothing magic about it, and it makes it more explicit what the function will return.


A bird in the hand.


A sparrow in hand is better than a pigeon on the roof.


And where does the stone fit in with these two birds?


It's rolling into a mossy gander, or something.


gotta wait til one of them gets the worm, then you find out


I never heard of sparrow pie.


Thanks! The Pogocache sharded hashmap design is optimized for extremely low contention and good memory locality. It super rare for any two threads to ever wait on the same key. That's the biggest part and it's all in the src/pogocache.c file. But the network layer is finely tuned too.

Mostly I perfed and profiled ad nauseam, monitoring cpu cycles along the way. I found that keeping a focus on latency and cycles was primo, and the rest fell into place.


Thanks!


Thanks you for the blog post about TG when it came out.


Glad to bring another one into this world.


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

Search:

HN For You