Live data from Hacker News

Go Data Structures: Interfaces (2009)

research.swtch.com

61–70 of 80 posts

Re: Go Data Structures: Interfaces (2009)

#61

The comparisons to python are a bit dated now. All of the examples can be implemented in python using typing extensions [0] and statically checked before runtime using mypy [1]. [0] https://docs.python.org/3/library/typing.html (from Python 3.5 - released Sep 2015) [1] https://github.com/python/mypy (v0.1 released Sep 2009)

More specifically, you can do interfaces with Protocol[0]. The main problem with it seems to be as soon as you a single Protocol mypy becomes extremely slow.

[0] https://docs.python.org/3/library/typing.html#typing.Protoco...

Re: Go Data Structures: Interfaces (2009)

#62
post #37

Earlier quoted context omitted.

> Python was the first language I made money with. However, these days, I struggle to read and make sense of type-ridden, generic-filled, Pydantic-infested Python code. I'm in the same boat. Python was great when it was a snake. I liked additions like the "with" statement - they were very pythonic. I think it's good when the language evolves, although the direction Python took feels more like grafting - oh people lik…

Please state you musings about the async. I'm just getting into that right now and I wonder if my misgivings are a result of my age or a fundamental issue with the Python implementation of the concept. Seriously, all and any insight and advice appreciated. Thanks.

Here's a good one: https://journal.stuffwithstuff.com/2015/02/01/what-color-is-...

The problem is futures (async/await) as a concept; JavaScript, Rust, etc all have the same problems.

Take CSP by contrast: https://en.wikipedia.org/wiki/Communicating_sequential_proce...

Any Go function can take a channel, return a channel, or use a channel (and spawn goroutines) internally, unbeknownst to the caller/callee. It may lead to some bad design decisions (code that must not be async may never be), but it won't get in your way when you least need a refactor.

Re: Go Data Structures: Interfaces (2009)

#63
post #55
post #37

Earlier quoted context omitted.

> Python was the first language I made money with. However, these days, I struggle to read and make sense of type-ridden, generic-filled, Pydantic-infested Python code. I'm in the same boat. Python was great when it was a snake. I liked additions like the "with" statement - they were very pythonic. I think it's good when the language evolves, although the direction Python took feels more like grafting - oh people lik…

Re tuples, I guess you mean the multiple return values, and this assignment form: https://go.dev/play/p/vxm6lV7JS4z However how would real first class tuples be an improvement in Go? Alef had them, and allowed various manipulations, as well as returning them, and passing them to functions. I note that they are present in Hare, but not present in Odin. Where the latter has the Go inspired multiple return values, but (…

My issue with Go's implicit tuples is similar to the pre-1.18 generics built into the language. We've had generic append since before 1.0, but it was "magical", you couldn't write your own generic append for e.g. a custom container. We've later managed to add generics in a way that didn't make append, make, etc seem out of place; but make remains a function with an optional, typed second parameter, IIRC the only one of its kind.

The implicit tuples seem just as magical. You can have func f()(int, error), but a:=f() is an error. It's arguably better than Lua (which ignores the second value), but arguably loses to Python (which returns a proper, first-class tuple).

Similar with destructuring. You can have g() struct{int;error}, but not i,err:=g() or struct{i, err} := g(). You can have f()(int, error), but again not a:=f(). You can have h(int, error) with h(f()), but that's a hardcoded special case, and somewhat unintuitive, since it violates x:=f(); h(x) - which would however hold in case of returning a struct. Go is just less composable, full of arbitrary exceptions and edge cases.

(I do still love it though.)

Re: Go Data Structures: Interfaces (2009)

#64
post #37
post #20

Earlier quoted context omitted.

One thing I like about Go is that you can read a decade-old blog and still find it somewhat relevant. Python was the first language I made money with. However, these days, I struggle to read and make sense of type-ridden, generic-filled, Pydantic-infested Python code.

> Python was the first language I made money with. However, these days, I struggle to read and make sense of type-ridden, generic-filled, Pydantic-infested Python code. I'm in the same boat. Python was great when it was a snake. I liked additions like the "with" statement - they were very pythonic. I think it's good when the language evolves, although the direction Python took feels more like grafting - oh people lik…

Wow, we're on pretty much the same path.

Loved Python when I got into it circa 2011. Didnt have prior programming experience, minus basic BASIC and HTML. It was simple enough and the stdlib include enough things to get me going, but it had enough complexity to intrigue me to dive deeper (list comprehensions, bytes vs strings, inheritance vs composition) and I think I learned a ton about programming thanks to it.

But these days when I see modern Python, it looks "uncomfortable". It has so many features, and so many ways of doing things that just figuring that out feels like a massive time sink.

I write server-side software with Go now. I feel like with Go I can just sit down and start solving problems. That applies even to sitting down and diving into a 10 year old codebase.

Re: Go Data Structures: Interfaces (2009)

#65
post #63
post #55

Earlier quoted context omitted.

Re tuples, I guess you mean the multiple return values, and this assignment form: https://go.dev/play/p/vxm6lV7JS4z However how would real first class tuples be an improvement in Go? Alef had them, and allowed various manipulations, as well as returning them, and passing them to functions. I note that they are present in Hare, but not present in Odin. Where the latter has the Go inspired multiple return values, but (…

My issue with Go's implicit tuples is similar to the pre-1.18 generics built into the language. We've had generic append since before 1.0, but it was "magical", you couldn't write your own generic append for e.g. a custom container. We've later managed to add generics in a way that didn't make append, make, etc seem out of place; but make remains a function with an optional, typed second parameter, IIRC the only one…

Sorry, but your response seems to be about consistency, or "purity" at some level.

While what Go has may be inconsistent, what functional impact does that have?

I can't see a need for 'de-structuring' as such, absent tuples. Even if it had real first class tuple types, like Alef did, what would one do with them? As I indicated, I'd not want to store them (other than holding in locals), prior to use.

As I recall, Alef did support de-structuring with tuples, as well as re-structuring. One could assign either way between an unnamed tuple, and an 'aggr' (it's name for a struct).

So at most I'd want to break them apart, which the return value thing gives.

Hence if I was creating Go 2.0, I can't see why I'd want to add first class tuples, but could see a use for adding tagged unions.

Re: Go Data Structures: Interfaces (2009)

#66
post #56

Earlier quoted context omitted.

[flagged]

[flagged]

The context problem is really annoying when using go. Many functions unnecessarily adding a context parameter so they can cancel a task. They made such nice syntax sugar for channels, why not also context?

Re: Go Data Structures: Interfaces (2009)

#67

Earlier quoted context omitted.

The mutability is a red herring here. It depends on what methods your object has and where the generic type resides within the signature. It just so happens that an immutable array has only one relevant "method": get :: Int -> T Here, T is on the right/return side, therefore an immutable array type would be covariant. But a mutable array also has a set :: Int, T -> void which has T on the left/parameter side and ther…

This setImmutable would return a new instance of Array which would not be Array like the original, and would contain any mix of cats and dogs. So immutability resolves the covariance problem, I think?

[deleted]

Re: Go Data Structures: Interfaces (2009)

#68

Earlier quoted context omitted.

The mutability is a red herring here. It depends on what methods your object has and where the generic type resides within the signature. It just so happens that an immutable array has only one relevant "method": get :: Int -> T Here, T is on the right/return side, therefore an immutable array type would be covariant. But a mutable array also has a set :: Int, T -> void which has T on the left/parameter side and ther…

This setImmutable would return a new instance of Array which would not be Array like the original, and would contain any mix of cats and dogs. So immutability resolves the covariance problem, I think?

My main point was that mutability and covariance are two orthogonal concepts that just happen to overlap here due to function signature shape. But it seems that you are right, I cannot think of any expression that would type-check with Array but not with Array. ChatGPT was very unhelpful in trying to produce a counterexample, since it probably trained on too many entry level stackoverflow posts about this issue.

Re: Go Data Structures: Interfaces (2009)

#69
post #65
post #63

Earlier quoted context omitted.

My issue with Go's implicit tuples is similar to the pre-1.18 generics built into the language. We've had generic append since before 1.0, but it was "magical", you couldn't write your own generic append for e.g. a custom container. We've later managed to add generics in a way that didn't make append, make, etc seem out of place; but make remains a function with an optional, typed second parameter, IIRC the only one…

Sorry, but your response seems to be about consistency, or "purity" at some level. While what Go has may be inconsistent, what functional impact does that have? I can't see a need for 'de-structuring' as such, absent tuples. Even if it had real first class tuple types, like Alef did, what would one do with them? As I indicated, I'd not want to store them (other than holding in locals), prior to use. As I recall, Alef…

> Sorry, but your response seems to be about consistency, or "purity" at some level.

> While what Go has may be inconsistent, what functional impact does that have?

Same reasons why Go fixed C's: inside-out type declarations, function pointer syntax, ERRNO, headers, macros, signal handling, UB, all the things that technically had no "functional" impact but still directly contributed to consistency, ergonomics, clarity, ease of comprehension, and (either by proxy or directly) correctness.

> I can't see a need for 'de-structuring' as such, absent tuples.

Your playground example of a, b = b, a is not destructuring a tuple in action? It's basically the same syntax / mechanism as Python's destructuring assignment, which existed since before Go (except Python's was always more powerful).

It's almost like you can do everything you want with a tuple in Go, except for actually holding it in your hand.

> Even if it had real first class tuple types, like Alef did, what would one do with them?

Similar things you'd do with a function without a name - work directly with the data at hand, without having to do the extra round trip to the attic to declare its name or shape.

> Hence if I was creating Go 2.0, I can't see why I'd want to add first class tuples, but could see a use for adding tagged unions.

That would probably break Go. I liked Chris Siebenmann's take on the subject:

https://utcc.utoronto.ca/~cks/space/blog/programming/GoUnion... https://utcc.utoronto.ca/~cks/space/blog/programming/GoUnion... https://utcc.utoronto.ca/~cks/space/blog/programming/GoUnion...

Meanwhile tagged unions bring you virtually all the way to ADTs, where pattern matching (generalised destructuring) is basically a must.

(By the way, Python stumbled really badly when it added pattern matching without even having proper structs. It's almost comical, given def __init__(self, ...), that should've been gone as a part of the 3.0 break-the-world.)

Re: Go Data Structures: Interfaces (2009)

#70
post #69
post #65

Earlier quoted context omitted.

Sorry, but your response seems to be about consistency, or "purity" at some level. While what Go has may be inconsistent, what functional impact does that have? I can't see a need for 'de-structuring' as such, absent tuples. Even if it had real first class tuple types, like Alef did, what would one do with them? As I indicated, I'd not want to store them (other than holding in locals), prior to use. As I recall, Alef…

> Sorry, but your response seems to be about consistency, or "purity" at some level. > While what Go has may be inconsistent, what functional impact does that have? Same reasons why Go fixed C's: inside-out type declarations, function pointer syntax, ERRNO, headers, macros, signal handling, UB, all the things that technically had no "functional" impact but still directly contributed to consistency, ergonomics, clarit…

> Similar things you'd do with a function without a name - work directly with the data at hand, without having to do the extra round trip to the attic to declare its name or shape.

Note that in Alef, tuples are essentially a dual for an aggr, but with unnamed fields. So one always has to (explicitly, or implicitly via inference) declare its 'shape', in terms of number of members, and type of members.

So one could declare:

    tuple (int, byte *, int) t;
Then manipulate 't', one could also have a function return a tuple as in:

    tuple (int, byte *, int) something(int x) { /* ... */ }
Then handle its return value either as:

    t = something(2);
or

    byte *str; int value;
    (nil, str, value) = something(7);
However the tuple 'shape' is always statically determined. Is that in your view satisfactory, or not?

Or do you desires something where the tuple is an entirely dynamic type, sort of akin to syntax sugar on top of '[]interface{}'? More akin to the sort of dynamic thing which Python offers?

Such that one can potentially have a program run, and each call to a given function returning a tuple may have different numbers of elements, potentially of different types within it. So that for said program, if the function return value depended upon input data, one could not determine the full set of tuples which may be returned?

Post reply on HN