Trade-offs for whom or with what in mind? the compiler or the programmer?
That's the "philosophical" difference between the Rust team and the Go team.
Even with two wildly different approaches to language design, each has their place, and their own set of drawbacks.
[0] https://medium.com/keepsafe-engineering/kotlin-vs-java-compi...
> With the Gradle daemon running and incremental compilation turned on, Kotlin compiles as fast or slightly faster than Java.
But frankly, comparing Go to Java when things like Rust exist ... seems analogous to comparing the z80 to the AVR when 32-bit ARM cores exist.
Example: https://blog.chain.com/bulletproof-multi-party-computation-i...
(I love both dynamic and static typing. I think dynamic type systems are more useful than basic static type systems, but also really enjoy more expressive static type systems.)
There's also a recommended way of dealing with errors. I may not state it correctly but basically you build a pipeline of operations for a data type that represents the arguments (or data) of the operations. For example, to compress an image given a URL:
type Image struct {
src string
bytes []byte
width uint
height uint
err error
}
func NewImage(src string) Image {
return Image{src: src}
}
func (img Image) Get() {
if err != nil {
return
}
...
// Set error value if this operation fails
}
func (img Image) Compress {
if err != nil {
return
}
...
// Set error value if this operation fails
}
func (img Image) Err() error { return img.err }
img := NewImage("https://image.src/random-image.png")
img.Get()
img.Compress()
if img.Err() != nil {
// handle error just once
}1: you must do this wrapping yourself, for everything you wish to simplify, as few libs do it.
2: you now have non-standard error handling and your tools will not warn you if you handle it wrong.
the second one, to me, is borderline fatal for this pattern. You can't look at this code and realize it's missing error handling (or doing it incorrectly), and you can't run `errcheck` to tell you that e.g. you're missing `err := img.Get()`.
What are some cases where errors can be ignored? And if they can be, are these neccesarily some sort of "status" rather than "error"?
One could argue that the side effect is part of the error, and really what you are ignoring are the details of an error (e.g. did the config entry fail to load because the config file wasn't found, because of filesystem permissions, or because the particular configuration key wasn't present?)
var s Settings
if s, err := load_settings(); err != nil {
s = defaults()
}
Where is the unhandled error?Here's a playground showing the issue: https://play.golang.org/p/eE0HEZx1MJu
Go is full of nice little foot-guns like that :)
You would want to also have 'var err error' above the block and use '=' instead of ':=' to fix this sort of issue.
package main
type HowOdd interface {
Poke() string
}
type AConcreteThing struct {
}
func (t *AConcreteThing) Poke() string { return "hehe" }
func DoAConcreteThing() *AConcreteThing {
return nil
}
func DoAThing() HowOdd {
return DoAConcreteThing()
}
func main() {
lolWhat := DoAThing()
if lolWhat != nil {
panic("How could this happen?")
}
}
I understand that the interface at the bottom is a non-null interface containing a null value, but...damn, that sucks.How likely is the error going to happen, if you know (through tests and everything) that the query is correct?
it can only happen in two scenarios:
1. the database has serious problems 2. the driver is incorrect
in normal cases you would probably handle that with a middleware in classical languages. i.e. you would have a middlewre that catches exceptions and handle the error there (logging, paging, whatever) and maybe show a nice looking "we are experience problems now"-page.
in golang this is a little bit harder, since you would need to handle the error by every caller and with the default http interface you would actually need to call your "handle default error" in every http handler.