5 ms·
> [Go] is forgiving enough that you can do exploratory programming in it. I agree with most of your post, but I’m not sure I would describe Go as “forgiving”.
by pansa2 6y ago
> [Go] is forgiving enough that you can do exploratory programming in it.
I agree with most of your post, but I’m not sure I would describe Go as “forgiving”. In fact, it’s well known for being strict. For example, exploratory programming would be significantly easier if the Go compiler could (optionally) ignore unused variables and unreachable code.
I’ve also found exploratory programming in Go is hindered by needing to frequently cast between different integer types. Maybe I’m doing something wrong, but my Go code is often littered with casts between different integer sizes and signedness. It’s much easier with Python’s arbitrary-precision integers.
- boyter 6y agoWhat I mean is that while the compiler is strict its fairly easy to throw something together that mostly works. The large standard library really helps there. It's certainly not as easy as in Python though.
- rob74 6y agoOk, let's say that it's more suitable to exploratory programming than other compiled languages? On one hand, yes it's strict about unused variables, but other features (e.g. fast compile times) more than make up for the disadvantages.
- kstenerud 6y agoI maintain a modified compiler (https://github.com/kstenerud/go/blob/master/README.md#the-go-programming-language https://github.com/kstenerud/go/blob/master/README.md#the-go...) that can issue warnings instead for unused things. I use it as my daily driver for go development. main.go: package main import "fmt" func main() { var start int = 1 breakOuter: // for x := start; x < 10; x++ { for x := 3; x < 10; x++ { for y := 0; y < 10; y++ { result := y * 10 + x // fmt.Printf("Result: %d\n", result) // if result == 42 { // fmt.Printf("Breaking") // break breakOuter // } } } } Building: $ go build # example ./main.go:3:8: imported and not used: "fmt" ./main.go:8:5: label breakOuter defined and not used (compilation fails) $ go build -gcflags=-warnunused # example ./main.go:8:5: Warning: label breakOuter defined and not used ./main.go:3:8: Warning: imported and not used: "fmt" ./main.go:6:9: Warning: start declared and not used ./main.go:12:13: Warning: result declared and not used (compilation succeeds)
- rat9988 6y agoThat's cool! It is so annoying to just try to try something fast, and then the compiler stops you...
- sacado2 6y ago> Maybe I’m doing something wrong, but my Go code is often littered with casts between different integer sizes and signedness. It can actually be a feature, and one of the things that brought me to go, as you can define your own integer (or float, or string, etc.) types, thus making them incompatible with each other: type distance int type speed int func distFor(d distance, t time.Time) speed { ... } ... x = distFor(x, t) // Oops, that's probably a bug! Not many languages let you do this, especially back then. But yeah, not great for exploratory programming.
- mikekchar 6y agoThis is probably the biggest thing I wish was easier to do in Rust. You can make "newtypes" by wrapping the value in a tuple (that gets compiled away), but it's a fair amount of boilerplate or macros to make the newtype useful. Once you have what you need, it's fine, but it's even less convenient for exploratory programming ;-)
- hoseja 6y agoOh, Rust does not have elegant strong typedefs? Bummer. Are they at least planned? It's such a boon for type correctness/safety.
- abjKT26nO8 6y agoIt does have them: https://doc.rust-lang.org/book/ch19-03-advanced-traits.html#using-the-newtype-pattern-to-implement-external-traits-on-external-types https://doc.rust-lang.org/book/ch19-03-advanced-traits.html#...
- hoseja 6y agoI'm sorry but that does not look like an elegant first-class language construct, more like a pattern workaround.
- 6y ago
- gerbilly 6y agoWhen programming in Java, I routinely run code that has compile errors in it. As long as my execution path doesn't hit any code containing errors, I can run debug and even modify code in the debugger. That's exploratory programming.
- LanceH 6y agoI had the same opinion you did until I went to a Go meetup and everyone else was a C programmer. Coming from Ruby, Go wasn't expressive or forgiving. But everyone coming from C thought it was wonderful. Personally, I feel you with respect to casting integer types. I'll code away with int's until something suddenly needs an int64 to use a package and I have to cast everything or refactor everything to int64. I once commented in a thread where people were asked, "In hindsight what feature would you like in Go?" I said that int should just be an alias for int64 (and float == float64), since these were the defaults in the stdlib. I was downvoted into oblivion in a thread on hypotheticals. I understand the historical machine dependent 32/64 difference, but since the stdlib made a choice, the default should line up nicely. That said, I mostly run into this in Project Euler problems, so not in my day to day work.