Their code is full of things like: type fileOps []any // []T where T is (string | int64) Go does not have neither generics nor union types. So people have to do this kind of thing :( I feel sorry for them. Reminds of Java 4 (15 years ago or something) where code was full of this crap: List /* */ values; Map /* */ map; Some devs spent a whole week doing nothing other than removing those commented out generic type decl…
Go has had generic List and Map since before Go 1.0, though. It's really interesting you used those as your examples because that need was fully met in a type-safe way already, and other examples are actually much rarer to come by.
Go Replaces Interface{} with 'Any'
151–160 of 481 posts
Re: Go Replaces Interface{} with 'Any'
#152Earlier quoted context omitted.
In semantic versioning, going from 1.X to 2.X is only indicated when there are incompatible API changes. Adding generics doesn’t break compatibility with preexisting Go code, so it’s unnecessary to increment the major version.
Sure, but semantic versioning really is the wrong kind of versioning to use for a language. The major version should represent major language changes, not whether its a breaking change or not, semantic versioning isn't somehow magically a "good" way to version. It's useful for libraries / dependencies where you are dealing with many different libraries and just want to know you can upgrade without having to deal with…
Re: Go Replaces Interface{} with 'Any'
#153Earlier quoted context omitted.
you can map on ok which is an alias for map_ok and then map_err for errors and or_else or_throw etc. that's similar to what Java does with the Optional type, not great, but not bad either the alternative is checking for nulls which is worse in any possibile way I usually implement something like Kotlin Result when I have to code in Java with a couple of static helpers to build the result: Result.success(T) Result.fai…
I also made a library for working with `{:ok, value}` and `{:error, reason}` in Elixir: https://github.com/linkdd/rustic_result Thanks to the pipeline operator and pattern matching, it makes pretty easy to read pipelines. It does not completely replace the with statement (that was not the point) but it simplified a lot of code.
Elixir is my daily drive and working in Java made me miserable until I started working around the lack of pattern matching facilities
Error handling is the worst part, I think a simple
switch (retval) {
Ok(val):
...
break;
Error(err):
...
would make Java much more pleasant, even without full pattern matching everywhere.Re: Go Replaces Interface{} with 'Any'
#154After generics (coming soon), a proper sum type and then I'll shut up.
Re: Go Replaces Interface{} with 'Any'
#155Earlier quoted context omitted.
> However, the topic is errors, not exceptions. Idiomatically, go uses errors for the purposes other languages use exceptions, so if this makes debugging harder, it's an important consideration.
That is also true of most languages. Java (and Javascript in its attempt to copy it) are about the only languages that actually promote using exceptions for errors, and in hindsight I think we can agree it was a poor design decision. That doesn't stop people from trying to overload exceptions in other languages, Go included, but in terms of what is idiomatic... However, the question was asking what is different about…
Python does. Ruby does. It's not just Java and JS. Go is very open about its approach being a departure.
> And actually, many APIs in the wild do represent errors as integers.
Many, many APIs in the wild are implemented in (or meant to be consumed from) C, which doesn't even have exceptions, so not using exceptions makes sense for them.
Very often idiomatic non-C host language wrappers for those APIs will fire exceptions when they get an error return.
Re: Go Replaces Interface{} with 'Any'
#156Earlier quoted context omitted.
Current state of the art: func read_file(filename string) (string, error) { return "", errors.New("oops") } func foo() error { a, err := read_file("a.txt") if err != nil { return errors.New(fmt.Sprintf("read a: %s", err)) } b, err := read_file("b.txt") if err != nil { return errors.New(fmt.Sprintf("read b: %s", err)) } // do stuff with a and b return nil } func main() { err := foo() if err != nil { fmt.Fprintln(os.St…
Your code is wrong. It would normally be written something like this: func read_file(filename string) string { panic(FileNotFound{filename}) } func foo() { a := read_file("a.txt") b := read_file("b.txt") // do stuff with a and b } func main() { defer func() { if err, ok := recover().(FileNotFound); ok { fmt.Fprintf(os.Stderr, "file not found: %s\n%s\n", err.filename, err.Stacktrace()) } } foo() } However, exceptions…
> Your use of exceptions for flow control (i.e. goto) is considered harmful
Exceptions are a way to delegate error handling to the caller by giving them informations about the unexpected behavior. It implies that the expected behavior is the "happy path" (everything went well) and any deviations (errors) is unexpected.
This is far from a goto because you can have `try/finally` blocks without catch (or defer in golang).
Also, exceptions are just a kind of algebraic effects that do not resume. There was a proposal to JS for this: https://github.com/macabeus/js-proposal-algebraic-effects
This is also easier to test. assertRaises(ErrorType, func() { code... })
Almost every Go library I've seen just return an error (which is just a string), you'd need to parse it to assert that the correct error is returned in special conditions.
Re: Go Replaces Interface{} with 'Any'
#157Earlier quoted context omitted.
I’m not a typescript person, but to be fair to typescript, its type system is still much more expressive than Go’s, even with the generics addition
Typescript is stricter and safer while also being less obtrusive than Go
I like Typescript a lot but the reality of Typescript development is not great.
Re: Go Replaces Interface{} with 'Any'
#158Earlier quoted context omitted.
Sure, but semantic versioning really is the wrong kind of versioning to use for a language. The major version should represent major language changes, not whether its a breaking change or not, semantic versioning isn't somehow magically a "good" way to version. It's useful for libraries / dependencies where you are dealing with many different libraries and just want to know you can upgrade without having to deal with…
Sounds like you think this is some kind of "Web 2.0" situation, but that was just a marketing term. Languages are software; they are dependencies of other software (the only unavoidable dependency!) and as such should absolutely be versioned. Versioning isn't for marketing or providing easy ways for users to remember when features were released. It's a tool for change management. Exciting features often come with bre…
Semantic versioning is an approach to versioning. It's an approach which, as GP stated, was designed specifically to help with dependency updating.
GP isn't proposing that languages shouldn't be versioned, they're saying that semantic versioning is the wrong approach to versioning for a language.
Re: Go Replaces Interface{} with 'Any'
#159This is fantastic. It'll make Go feel much less weird. eg from the diff: []interface{}{1, 2.0, "hi"} -> []any{1, 2.0, "hi"} Now that Go is going to have generics, all we need is sugar syntax for early return on error -- like more modern languages such as Rust and Zig have -- and Go may finally be pleasant to program in!
Re: Go Replaces Interface{} with 'Any'
#160Earlier quoted context omitted.
I was in an interview not long after format strings in Python came out (for example, print(f”Hello, {name}”) rather than print(“Hello, %s”, name)) and the interviewer thought I was confusing languages and features, asserted this fact strongly, and was pretty surprised when it worked, but I think overall I lost points because the interviewer lost face. C’est la vie.
As a very casual Python user, I didn't know about that! that's great.
I especially like f"{foo=}" for debugging.