3 ms·
Go has maps already. A set is just a map where the key and value are the same thing.
by _wldu 5y ago
Go has maps already. A set is just a map where the key and value are the same thing.
- yashap 5y agoSets tend to have methods like difference, union and intersection - with a map[T]bool, if you want to find the difference, union or intersection of 2 sets, you have to do all of that with much more verbose (and error prone) loops. Also, the type being a set carries a semantic meaning, with a map[T]bool it’s not obvious from the type alone that we only care about the keys, not the values.
- thegeekpirate 5y ago> with a map[T]bool This takes up unnecessary space—use map[T]struct{} instead, which also explains to anyone reading the code that the value isn't used.
- randomswede 5y agoThere is a slight difference between the two. With a map[†]bool, you can do something like: if myset[thing] { ... } With a map[T]struct(), you end up with: if _, ok := myset[thing]; ok { ... } Sometimes, the saving in space is TOTALLY worth the extra verbosity. Sometimes, the slight clarity from "non-existent keys return the zero value" wins.
- morelisp 5y agoWell, now there's no excuse for not having `myset.Contains(thing)` (though there really wasn't before either) which is even clearer.
- thegeekpirate 5y agoYou've also opened yourself up to bugs by allowing the map values to be "false". Using a "set's" value in an if statement doesn't make sense either, compared to if _, exists := something[item]; exists { ... } which is explicit regarding what's actually going on. As Rob said, "Clear is better than clever." https://www.youtube.com/watch?v=PAAkCSZUG1c&t=875s https://www.youtube.com/watch?v=PAAkCSZUG1c&t=875s I also don't want to be hunting down whoever creates a map[T]bool and doesn't leave a comment explaining it's a set ;) Hopefully we won't have to worry about it for much longer regardless, since I imagine we'll be using proper sets (with methods) some point in the near future.
- randomswede 5y agoI would say that "exists in the set" is determined only and exactly by "mySet[thing]" returning true, not that there happens to be a key in the map. But, that's one of those "requires extensive documentation" (and ideally, wrapping in a custom type and provide methods for checking and manipulating the set(s)).
- yencabulator 5y agoNow every range over your set is likely to be a bug. `map[T]bool` is simply a bad design to use.
- randomswede 5y agoHow? Why? If you use the map[T]bool, you obviously need to pay attention to the bool value, even in a range. Whereas in map[T]struct{} you don't need to pay attention to the values. In either way, even with that type of data type underlying a set, I would (probably) provide a functional API to interact with it.
- yencabulator 5y agom["x"] = foo() for k := range { // if foo returned false, this is buggy }
- randomswede 5y agoYes, as I said, if you use a map[T]bool, you need to use something like: for k, v := range m { if v { } } But it also allows you to use "if m[key] { ... }". It is literally a trade-off for what convenience you want. And in both cases, you should (probably) wrap an abstraction around the raw map.
- glenjamin 5y agoAnd now with generics we have a way to make this decision/optimisation once, and have everyone else benefit from it without having to be aware of the details!
- deleted 5y ago[deleted]
- papageek 5y agoI wish this had been map[T]_ vs empty struct.
- fileeditview 5y agoYou can also use a map[T]struct{}. I like bool better because of the default value behavior but struct{} is very clear and does not take extra memory.