8 ms·
I can feel the pain on the Sort issue. I've personally found sorting annoying in Go - I had a bunch of structs representing data entities from a database that
by mattlondon 11y ago
I can feel the pain on the Sort issue. I've personally found sorting annoying in Go - I had a bunch of structs representing data entities from a database that all had the same field and I wanted to be able to sort them by this field.
Seemed like a LOT of work (basically implementing the same sort that was 99% identical for every struct) or use weird reflection-workarounds to get this to happen. In Java I would not even given this a second thought and be back to coding up the important part of the code ages ago.
I am a new go-lang user so would love to know what the best approach to resolve this is without a) repeating the same thing for every struct, or b) relying on "unsafe" reflect techniques (since AppEngine rejects code that does that) - surely sorting structs is a super-common, basic thing for a systems language? I've seen someone just nonchalantly say "Use interfaces" but I'm not sure still.
I like the language generally but this is a real "WTF?" moment for me.
- xiaq 11y agoWrite a code generator. That's the best solution at this moment.
- enneff 11y agoOr, y'know, just copy and paste the trivial code. It should take all of 30 seconds. Not saying that it's pretty, but it's quick and easy.
- junke 11y agoAnd that's exactly why I am not convinced that Go is as maintainable as often claimed. 30 seconds for you, but how many hours for the poor souls who will come after you and ask: should I change this copy too or is it a separate case? It reminds me of this: http://typicalprogrammer.com/abject-oriented/ http://typicalprogrammer.com/abject-oriented/
- enneff 11y agoThis thread is about sort interface implementations. Their general form will never change, and the only specifics unique to any given copy are those specific to their type. It is obvious to any Go programmer what can and cannot be changed in this situation.
- junke 11y agoThe thread was more about mattlondon's problem with sorting according to the same key in different structs. I used of modified version of this example[0] to illustrate what I think is his problem[1]: you can sort circles and planet by radius, and probably many other things in the original case, but you are required to copy-paste the definitions. I can understand that instantiating templates by hand is not so bad. But once it is written, maintaining the code is not so obvious for someone not acquainted with it. Did I introduce a bug or not in the code? Not easy to tell without context. [0] http://stackoverflow.com/a/28999886/124319 http://stackoverflow.com/a/28999886/124319 [1] https://play.golang.org/p/Dq0AJjkhhr https://play.golang.org/p/Dq0AJjkhhr
- jhalderman 11y agoWhy not write an interface for getting the radius and a radius sorter for sorting on that interface? I made a modified version of your code to illustrate. https://play.golang.org/p/Ya7tUhDnO2 https://play.golang.org/p/Ya7tUhDnO2 *edited a typo
- junke 11y agoThanks a lot for your example. I would certainly take this approach and I am happy that you took the time to write it. I feel a little sorry for you because I put a trap for the parent poster in the original code. I wrote "a[j] < a[i]". You "fixed" it while refactoring, which would be the good thing to do if I made a typo. If however I really wanted to sort circles differently from planets, then you made an error while refactoring what looked like copy-pasta but wasn't. My original point was that when you "have" to copy-paste, you cannot clearly see what is or isn't part of the copy and what is new. You found a way to rewrite the code without much copy- pasting, and I am happy to see that. Still, in other places where code duplication arise, there could be similar problems from a maintenance point of view.
- iopq 11y agocommit c270f19d456e862aeb559098fa32d36fbc5329a0 Date: Wed Apr 13 04:57:46 2016 -0700 fixing level selection again commit dae018e4f76db0e9da810b4560d6c8e1c7029048 Date: Mon Apr 11 07:06:47 2016 -0700 fixing level selection for hint case commit a754bcd0d09ab1e357ae28c8f06baf65d879878f Date: Sat Apr 9 02:33:14 2016 -0700 forgot to fix the level selection in the move case
- golergka 11y agoMaintenance.
- parenthephobia 11y agoWhat if I'd done that 20 times around my code-base and then later I discover there's an off-by-one error in the original code that's maybe been inherited into all 20 copies? If I could actually reuse code properly I'd only have to fix it once. Without effective code reuse, I have to hunt down the copies, each of which may have slight modifications to make them better fit their use case (and might be hard to grep for as a result), figure out whether or not the bug exists in that copy (and whether it can actually be triggered), and fix it there. The description of inheritance in http://typicalprogrammer.com/abject-oriented/ http://typicalprogrammer.com/abject-oriented/ seems relevant here. (Edit: Derp, junke got there way before me!)
- takeda 11y agoThen one day you find a bug in your code and now will have to find all copies of it and to make things worse someone else modified some of the copies so now not all of them are identical.
- junke 11y agoYou might be right, this is the best solution in Go at this moment, but that's a local optimum. You don't have to solve this kind of problems in many other languages. The generator given as an example in the official blog [0] is called "stringer". It is made of 639 lines [1] mixing ast parsing/traversing and printf statements. If this is what I am supposed to write then of course copy-pasting becomes a pragmatic alternative. [0] https://blog.golang.org/generate https://blog.golang.org/generate [1] https://raw.githubusercontent.com/golang/tools/master/cmd/stringer/stringer.go https://raw.githubusercontent.com/golang/tools/master/cmd/st...
- scotty79 11y agoOr go the JS route and write a transpiler. Language is lacking? Make a new one.
- louthy 11y agoOr just use a language that supports generics instead?
- sievebrain 11y agoThe first company to make a fork of Go that runs on the JVM and has compiler-specific extensions will make a ton of money, IMO.
- zzzcpan 11y agoThis will only target a very small group of developers, who are comfortable with JVM, but not with Java or Scala. I don't see any money there. JVM is a major drawback for any language. Many people don't even look at JVM languages.
- sievebrain 11y agoNo, it's the opposite. It would appeal to people who built large Go codebases and eventually realised that they were tied to a toolchain that was years behind the state of the art. A Go for the JVM would immediately give Go developers much better optimising compilers, high quality cross platform IDE-integrated debugging and profiling, much stronger garbage collectors, ability to access the large quantity of Java libraries that are out there, ability to mix in other non-Java languages too (javascript, ruby, R ...), code hotswap, better monitoring tools, a vastly larger standard library, better code synthesis tools and so on. The JVM is hardly a liability. It adds features and carries a cost, but Go is substantially similar to Java in many ways and getting closer with time. I do not see any credible plan from the Go developers to beat the JVM developers in terms of GC or compiler quality, for instance.
- 11y ago
- ball_of_lint 11y agoWouldn't that end up being essentially equivalent to adding generics to go?
- Loic 11y agoI had the same feeling first. But practically in my code, I found that ok, you need to copy/paste a bit first but then if it works it stays there, you are not "sorting" new kind of "types" every day. The time spent on coding is way more "around" the algorithms than "within" them. I suppose that we will see more and more code generators which will practically remove the need of generics. We already use them without complaining for serialization in JSON/Protocolbuffer/etc...
- jcoffland 11y agoIf you're copying and pasting then you're doing it wrong.
- chillydawg 11y agoNot in go. You're allowed to in go. Because some googlers reckon that's cool.
- coldtea 11y ago>you are not "sorting" new kind of "types" every day You'd be surprised.
- Loic 11y agoI am writing a chemoinformatics database, so for my practical use, these are a lot of lines of codes with pretty involved algorithms and I am practically not annoyed by the lack of generics. For the ones down-voting me, have you coded something in Go, big enough to be a real in production project, where at the end the lack of generics is a real issue (performance because using interfaces or maintenance because copy/paste to have the performance)?
- codygman 11y ago> For the ones down-voting me, have you coded something in Go, big enough to be a real in production project, where at the end the lack of generics is a real issue (performance because using interfaces or maintenance because copy/paste to have the performance)? Didn't downvote you, but yes I have.
- kqr 11y agoCompletely oblivious about Go, but can you not provide a key function to the sorter that reaches into the struct and pulls out the field you want to sort on? (And presumably explodes in some spectactular fashion if it doesn't exist.) Or is that the "unsafe" reflection you're talking about?
- XorNot 11y agoFor struct's at least, the answer would be to use an interface method which exposes the key field you want to use. This would be type-safe - you wouldn't be able to pass a non-conforming struct to the sorter. EDIT: I'd argue what we need in Go is something like a type-class for interfaces, so we can match on fieldsets the struct contains, and not just methods.
- mattlondon 11y agoI think matching on fieldsets would be the ticket here. I guess right now I could add a pointless no-op "marker method" to make each struct match a "CanBeSorted" interface, then have my sort function work in terms of things implementing CanBeSorted, but that does not guarantee the fields I want to use are there. Sigh. I am hoping that the "no backwards incompatible changes" thing Go has wont prevent fixing things like this sorting nonsense. Right now, whichever way I approach this sort of thing just feels icky.
- deleted 11y ago[deleted]
- inglor 11y agoThis is stupidly easy with http://dl.acm.org/citation.cfm?id=2738008 http://dl.acm.org/citation.cfm?id=2738008 - I opened an issue for considering something like this for go https://github.com/golang/go/issues/15295 https://github.com/golang/go/issues/15295 hopefully I didn't err in posting it :)
- brightball 11y agoCouldn't you create a common interface that you could use for the sort?
- deleted 11y ago[deleted]
- xiaq 11y agoNo, the sort package requires you to define methods on the slice of what you want to sort. For instance, if you defined a struct S, you need to implement Less, Swap and Len on an alias type of []S (since you cannot implement methods on slice types).
- parenthephobia 11y agoNo. There is no interface that "sortable" things implement, other than the empty interface, and no neat way to define one. Numbers and strings support <, but there's no way to specify operators in interface, and no way to specify operators for other types anyway. You could do type Comparable interface { Compare (x Comparable) int // -> -1, 0, 1 } func Sort (x []Comparable): []Comparable { /// ... } And whilst this Sort could work, how do you call it? []int isn't []Comparable, and can't be converted to one: you have to make a new array. Then, when you want an array of ints on the other end, you have to convert it back, which now involves run-time type assertions. Even an array of something that implements Comparable isn't compatible - it can't be, because Go doesn't know Sort won't take Bar[] and put a Foo in it, if Foo and Bar both implement Comparable. And, whilst you can define Compare for int, the other argument will be a Comparable, not a int, so you'll have to have a run-time type assertion for each comparison. Conversely you might try func Sort (x []interface{}, f func(interface{}, interface{})int) []interface{} { /// ... } You still can't sort []int, and your comparison function can't know it's receiving int, so it will have to type-assert both arguments at each comparison.
- rakoo 11y agoThe whole problem is that there is a common interface, but it's a PITA to reimplement it every time (which means copy-pasting a little less than 10 lines) when every other language gives you sorting with a single, simple, 1-line function (or even a single argument of an already existing function).
- ImJasonH 11y agoI made this: https://github.com/imjasonh/tros https://github.com/imjasonh/tros It's slower than doing it yourself but for normal-sized slices you shouldn't notice. Also https://github.com/bradfitz/slice https://github.com/bradfitz/slice which is similar but faster and relies on more unsafe black magic.
- tmaly 11y agoI agree with the Sort issue, I faced the same problem. However, I cannot see how generics would fit well into code that is supposed to be easier to understand and maintain.