4 ms·
I think the proposed alias has true merit in Go as has been shown by Russ Cox and in other places. What I'm a bit confused about is why it's sold as a transitio
by blixt 10y ago
I think the proposed alias has true merit in Go as has been shown by Russ Cox and in other places. What I'm a bit confused about is why it's sold as a transitionary tool but implemented as a feature.
If it's so easy and clean to use it may become a misused feature, causing developers to write "temporary" code that just lingers around forever because it's more convenient to let it be than to actually move to the new API. I'd draw parallels with imports in Go versus imports in Python. I would wager that a great majority of Python repos out there have lingering imports in some module that doesn't need to be there. But in Go I can guarantee that there are 0% unnecessary imports.
For example, the declaration could be obvious that this is for compatibility as opposed to a feature:
legacy const FUN_THINGS => funner.Things
Also, when compiling a package using the FUN_THINGS constant you'd be warned:
./main.go:10: using legacy alias: "clowns.FUN_THINGS" has moved to "funner.Things"
These small things would help prod developers to actually fulfill the transition as opposed to letting it linger.
- dilap 10y agoSo far, Go doesn't have warnings, which is great. Either it's an error, or it's nothing. This is great IMO, because I've seen too many codebases that just end up having infinite amounts of warnings that never get fixed, making them (1) useless and (2) annoying. (Extraneous imports is a great example of something that in most languages would probably be a warning (or nothing); I remember in the early days people bitched like crazy about it, but on balance it's really really nice. (goimports also removed a lot of the pain.)) I think it's clear that if this goes in, people will use it beyond just refactoring. Honestly, I'm ok with that, if it's restricted to just types. Here's something I've done from time to time: func now() time.Time { return time.Now(); } Just because typing time.Now() everywhere was getting tedious. Having a type that's an explicit alias doesn't seem too bad to me. type Time = time.Time Sure, it's an extra step of indirection, but a very easy one. (I feel like having variable aliases would be much more confusing, because variables are mutable.) === And it's not like the situation is that different from right now. For example, maybe I have some package with an api like: func DateMagic(t time.Time) time.Time OK, super-obvious what it's taking. Now maybe I'm using aliases and you see: func DateMagic(t Time) Time Hmm, not quite as obvious, now you have to go lookup type Time = time.Time But still today I can do func DateMagic(t x.Time) x.Time Hmm what's x? Oh import x "time" Of course it could get a little pathalogical... func DateMagic(t DumbName) DumbName type DumbName = time.Time but I feel like you're really trying there.
- Jabbles 10y agoYou can use var now = time.Now
- dilap 10y agotrue, tho slight savings in characters not worth the less-clear definition imo
- skj 10y agoIs that really less clear?
- dilap 10y agoI think so -- if I see this it's obvious now is a function. func now() time.Time { return time.Now() } If I see this: var now = time.Time My first instinct is, "hmmm, some kind of variable?" And then I have to remember, "oh yeah, it's just a variable that holds a function." Obviously not a big deal either way. (I think this further shows how type aliases would not be adding much possibility for confusion compared to what already exists in the language.)
- ithkuil 10y agobtw if you want you can explicit mention the type in the var declaration
- randomdata 10y agoOn the other hand, you may want to set `now` to return a deterministic time value when testing, which the variable allows.
- blixt 10y agoI don't think realiasing exported signatures is a good idea, in any language. However, doing what you do in your package as a private function is perfectly fine, that is for your own convenience. Regardless, I don't think the argument that the Go maintainers are making is that this is about number of characters saved. The point of an alias in the first place is to make it more feasible to carry out breaking API changes (which are an important part of any maturing API). So if aliases are introduced for the purposes of making API transitions possible over multiple commits, then I think they should be clearly designed as such. Which means that it shouldn't tempt people to do what you just described in your comment. Maybe that wouldn't be a bad thing, but if that becomes the ultimate use for the aliases, that use case should play a bigger role in the design of aliases. Because right now, as far as I can tell, they're being designed mainly for API transitions.
- crdoconnor 10y ago>I would wager that a great majority of Python repos out there have lingering imports in some module that doesn't need to be there. But in Go I can guarantee that there are 0% unnecessary imports. With a linter you can do that with python too.
- blixt 10y agoCertainly, and I can also type my JavaScript. But it doesn't happen more than maybe 1% of the time because optional good practices usually fall by the wayside. This is why Go's simple but strict rules are so key to keeping it clean. Again, I'm not opposed to the alias solution, I just don't think it should be added as a tool with optional good practices accompanying the design spec (e.g., "use it to transition an API and then remove the old aliases"). In his article, Russ argues mainly for the breaking API case, but ends with that general aliases (what was proposed for 1.8) are a promising solution. I think otherwise – a specific use case shouldn't necessarily be seen as an opportunity to apply a generic solution.
- crdoconnor 10y ago>Certainly, and I can also type my JavaScript. Running a linter that catches just unused imports is a one line command (30 seconds), whereas statically typing your javascript essentially requires a full rewrite (weeks or months of work). >This is why Go's simple but strict rules are so key to keeping it clean. There's value in being able to "dial up" the cleanliness as and when its needed. It's often a waste of time to focus on cleanliness of code that you're not sure is going to last. I wouldn't want unused imports to cause a compiler failure even though I run the linter and use that rule regularly.
- blixt 10y agoThat's just evading my point. Go doesn't dial up its cleanliness, it's just clean. And it already does cause a compiler failure if you have unused imports or variables.
- Merovius 10y agoAliases weren't only proposed as a way to implement gradual repairs (and the proposal, also, is for "a way to implement gradual repair", not so much "aliases"). There are several non-transitionary use cases given as a justification for aliases, when they where initially proposed. Examples are a) implementing the protobuf "public import" feature in generated code, b) providing drop-in extension packages for other people's code (for example golang.org/x/image/draw is an extension of image/draw) and c) exposing APIs from internal packages selectively. Personally, at least b) is definitely something I would use them for. It's just that a lot of people didn't clearly understand what the refactoring problem is, that aliases would solve ("just use a tool for rewriting things" was a common response, or "use versions") and how aliases solve it. So, this proposal is taking a step back; instead of necessarily pushing aliases, it now describes the refactoring problem that aliases solve and seeks a) consensus that this is a problem that go should solve systematically and b) what the mechanism is, that it should solve them with. Aliases are one proposed way. That's why I would be really annoyed, if something like compiler warnings or so would be introduced when you use them; if go gets aliases, I'd consider it stupid not to use them for all the other things that they are a good solution for. And I would use them as such and if people complained about compiler warnings, tell them to complain to the go team that they put warnings in for something that shouldn't be warned about.
- blixt 10y agoThese are fair points and I must've missed the elaboration on them when I looked at the proposal for aliases, as I was left with the feeling they were being pushed forward mainly to solve the gradual repair issue. I guess I have two points to make: 1) try to make a contained solution for a contained problem because the general solution may carry with it a number of unforeseen issues 2) if you do see an opportunity to apply a general solution, exhaust every use case of that solution and rewrite the problem statement to apply to all those use cases As for being really annoyed if there were warnings, that was exactly my point. :) Label them as something more specific (a solution to the repair problem) and make it difficult to use them for something else. That doesn't exclude a future, more generic solution – it just avoids unaccounted for problems.
- 10y ago