5 ms·
I think there is a difference, and for the worse: `0` is a perfectly valid integer value which can be used like any other value. `null` is a valid reference val
by Dewie 12y ago
I think there is a difference, and for the worse: `0` is a perfectly valid integer value which can be used like any other value. `null` is a valid reference value, but is invalid as far as dereferencing goes; refer NullPointerException. `0` has more potential for propagating through the program, and being erroneously used as a valid map value, while it should really be treated like a sentinel value by the program (no-value-in-map). A reference which is assumed to be valid can only propagate through the program to the point where it is dereferenced, in which case the erroneous assumption will be challenged.
It seems like the strong/weak typing distinction: one value can be used freely like any other value, since that is what it is. The other can only be used as a regular value to a degree: it can be passed around, but not actually used.
- ajuc 12y agoBTW, there's one more gotcha with java maps: public static void main(String[] args) { Map<String, String> testHashMap = new HashMap<String, String>(); Map<String, String> testTreeMap = new TreeMap<String, String>(); testHashMap.put(null, "foobar"); testTreeMap.put(null, "foobar"); System.out.println(testHashMap.get(null)); System.out.println(testTreeMap.get(null)); } This will throw NullPointerException at the last line :) For hashmaps it works, for treemaps not. Happened on production in my previous company (we used map2.get(map.get(...)) and used null rturned from the inner map to get the default value from the outer. Then we changed to tree maps to keep order when displaying the maps...
- NateDad 12y agoThis is one nice thing about go maps... They won't panic if you try to access a null map, they just return the zero value (and false). var m map[int]int = nil a, ok := m[1] // returns 0, false
- Dewie 12y agoThat doesn't seem nice if the map wasn't supposed to be nil (if you assume that failing fast on buggy behaviour is good). But I guess you might want to, on purpose, instantiate and use a map which is nil?
- NateDad 12y agoWhat's the difference between a nil map and a non-nil but empty map? You asked if the map had a value for your key, and it said no.
- Dewie 12y ago> What's the difference between a nil map and a non-nil but empty map? A nil map is the absence of a map. An empty map is an empty map. The distinction is clear.
- ajuc 12y agoI don't know go, but this seems very dangerous. I prefer Python solution - throw Exception, and if programmer want default - there's always defaultdict.
- NateDad 12y agoI don't think it's dangerous at all. What's the difference between an empty, non-nil map and a nil map? Why should their behavior differ? The fact that a map can be nil is effectively like an implementation detail. You asked for the value by a key, and the map tells you that key doesn't exist. Why should a map not having a value in it cause an exception? It's not exactly a rare occurrence. go supports this with the two value return, with the second value telling you if the key existed.
- ajuc 12y ago> Why should a map not having a value in it cause an exception? map controlCenters = database.getControlCenters(); // returns map column->value, nil if no connection int controlCentersInExistence = controlCenters["count"]; //FIXME - use the other syntax, I forgot how it looked like if (controlCentersInExistence == 0) { // someone nuked USA! WW3Manager.launchMissiles(); // we need to retaliate! }
- NateDad 12y agoSee, that's not a problem of the map, that's a problem of poor error handling. If for some reason database.ControlCenters() could ever not return a valid map, it would also return an error value. controlCenters, err := database.getControlCenters() if err != nil { return fmt.Errorf("couldn't get map of control centers: %v", err) } // now we know controlCenters is valid. controlCentersInExistence, ok := controlCenters["count"] if !ok { return errors.New("no count of control centers!") } // now we know the column existed if controlCentersInExistence == 0 { WW3Manager.launchMissiles() } Go's conventions are actually excellent at making this code MUCH more robust.
- anonymoushn 12y agoThis way the program will fail somewhere else long after the actual failure occurred. Great!