4 ms·
Interesting, I agree with the the main idea: in general I find Go a productive language, but there’s a few rough edges. The specific examples don’t ring true t
by materielle 2y ago
Interesting, I agree with the the main idea: in general I find Go a productive language, but there’s a few rough edges.
The specific examples don’t ring true to me though.
Instead of named arguments, use the functional optional pattern.
An ordered map can be implemented as a slice with a get function. If you want to stamp out some code duplication, Go has generics and iterators these days.
What I really miss are enums. Specifically, the ability to map two value sets to each other and get a compile time error if the mapping becomes stale due to a new value.
And other assorted stuff. Like better nil handling, the weird time and http client libraries, nil interfaces and slices, and so on.
- RSHEPP 2y agoOh interested in the issues with http clients you have? I think they are great to use for being right in the standard library. Only complaint I have is defaults for timeouts and such, but you make that mistake once and don't forget.
- materielle 2y agohttps://blog.carlana.net/post/2021/requests-golang-http-client/ https://blog.carlana.net/post/2021/requests-golang-http-clie... I don’t think that article discusses the timeout issue. So all the issues mentioned in that article, plus the timeout issue. The end result is you have to explain to every Go developer that they can’t use the http client as-is. Start searching for http client usages in GitHub. You’ll probably find more incorrect usages than correct ones. It’s a solvable problem, you write a wrapper http client once and tell everyone to use it. But it’s a nasty foot gun to have to explain all this.
- Groxx 2y agoI'll just throw in: If you use functional options, please don't implement them with closures. Closures aren't comparable, so there's essentially no way to build middleware that varies behavior based on those arguments. Just make a `type thearg string` or whatever instead. Very similar amounts of code, similarly hidden implementation, but MUCH more usable.
- kbolino 2y agoThe whole point of the "functional" options pattern is that the option's own identity or type doesn't matter, only its side-effects. If you do need to examine the option itself, you're either using the wrong pattern, or you should be using an interface with additional, self-descriptive methods instead. For example, I have used an interface similar to the following for a custom HTTP client wrapper (as discussed in another thread): type RequestOption interface { Priority() int8 Name() string Apply(r *http.Request) error } The Priority method might seem like overkill, but it was useful here because there are default options for the whole client and local options on each call, which have to be merged and applied in the proper order.
- Groxx 2y ago`==` is a useful side-effect, and violating it makes a type rather abnormal.
- kbolino 2y agoIf you're using the functional options pattern, and you're trying to == or type-assert one of the options, you're the one doing something abnormal. Maybe it makes sense in the broader context of what you're trying to do, but then I'd say that the functional options pattern isn't the right fit in the first place. Also, "side effect" in computer science has a pretty straightforward definition, and equality comparisons are not side effects.
- Groxx 2y agoSide effect: agreed, but the way you used it makes no sense in that definition (arguments cannot have side effects on a function call, they're resolved before the function is called), and the main other option in Go is to pass a struct or separate typed arguments which also has no side effects, and the only other interpretation is "the side effects you can trigger in the function based on the argument" which is identical in all scenarios... so I figured you were using it in the more colloquial way where it's closer "observable behavior [of the argument's type]". Or "the unintended consequences of a design decision".
- xyse53 2y ago> Instead of named arguments, use the functional optional pattern. Options pattern is an alternative, I use it frequently, but still miss named arguments and default arguments if I'm going back and forth with Python. - The options pattern is much more verbose to implement. - The defaults aren't as easily clear, they need to be documented and kept consistent. - You can't, or it's not as easy to, make some arguments required. - And, as a caller, if the API I'm using doesn't support them, I sometimes have to rely on comments to clarify what each arg is. For example, if a function takes a bools like `func MyFunc(dryrun, inverse bool, items ...string) error { ... }`
- mariusor 2y agoAlso the functional options pattern usually implies that there is an object on which the functions operate. Default values for parameters is something that can apply to any function, not just initializers. I wonder if parent could give us an alternative for strings.Replace using functional options.
- milch 2y agoThe functional optional pattern thing seems fine for constructors, but I wouldn't want to have to implement it for every single function. A lot of the times it is just about readability at the call site, e.g. (using the author's example) string.Replace(urlString, " ", "%20", -1) is less readable than string.Replace(urlString, replace: " ", with: "%20", maxReplacements: -1) Of course it's not often necessary, especially when you have a named variable string.Replace(urlString, charToReplace, escapedChar, REPLACE_ALL) But it can also be awkward to have to declare a variable for every arg, which is probably why python allows you to call it both ways. Plus the variable names and positional arg could not match up, which can be a source of hard to find bugs
- deleted 2y ago[deleted]
- cratermoon 2y agoI don't quite get the strings.Replace example when there's strings.ReplaceAll
- kokada 2y agoAuthor here. The fact that `strings.ReplaceAll` exists I think is a good argument for having default arguments, because I can't think of a good reason why we need a separate function for this case. But maybe it was a bad example. I remember that there is one function in `strings` that I almost always use the same value in every call I do because it is the correct value in 80% of the cases. I thought it was `strings.Replace`, but probably it is something else. If I ever remember which function it is, I will update the post.
- kokada 2y agoAuthor here. > The specific examples don’t ring true to me though. And I don't think it should. To start, the list is small because it is a work in progress, I plan to write more once I have more to talk. I didn't expect this post to hit HN that soon, but thanks to whoever posted this here. Got some really interesting points of view. But also they are particular pet peeves of mine, and don't necessarily reflect other people's experiences.