-
Notifications
You must be signed in to change notification settings - Fork 195
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Make maps not always use null
as default value.
#1005
Comments
I'm looking forward to be able to do a |
I feel |
He is only giving a example of the |
I'm also giving an example. My point is that |
I wonder whether this really covers the common case? It seems to me that there are two kinds of indexes into a map:
In the first case, users should prefer not to get a nullable return type, but should be mostly agnostic between throwing an exception or returning a default value (though they may prefer to get an exception since if they have a bug, the exception will surface). In the second case, it's not clear to me what users will mostly want.
So it's really not clear to me that getting a single default value is what users will want most of the time. I actually suspect that we would cover more use cases if we added a separate operator (maybe use the call operator) which indexed and threw if the value was not there. But really, this feels like something that would be nice to get data on. |
I agree @leafpetersen. In Ruby, a language I've spent a lot of time with, they support square brackets for "gimme the value or null" and I wonder if that sort of API would feel good to dart users. I know that I would like it and it's not that different from the methods on Iterable that take Using a lambda is a nice way to allow for new instances of the default value to be used on each fetch. For example, if you set the default value at Map construction time and you use a type like List, then each time you'd have a key miss, would you get a new List or a reference to the one default List instance created at Map construction time? If it's the latter then ant mutations to that List will likely result in surprises for other key misses that return a non empty List. Anyway, I think a fetch method might be a good alternative approach. |
cc @pq @bwilkerson I just noticed in passing that my last comment here was relevant to our discussion about gathering data. Could be a kind of interesting test case. How many uses of the map index operator:
There are other interesting things you could look for, but they might be harder to track, e.g. |
Is this still under consideration? |
I'd keep it open as an enhancement request, but it's not NNBD-specific. |
@leafpetersen The biggest problem with returning Indeed, I have run into multiple instances where not considering that a generic type could be With null safety, when you have a type |
It does make sense. This is an unfortunate but known limitation of using nullable types instead of option types. I wrote about this at length here. It's a trade-off. Dart can't represent nested nullable types like you might like in cases like this, but in return other idioms get simpler and easier. |
Also, you can tell the difference: Map<String, int?> numbers = {"1": null, "2": 2, "3": 3};
bool contains0 = numbers["0"] == null; // true
bool contains1 = numbers["1"] == null; // also true
bool contains2 = numbers.containsKey("2"); // unambiguously true |
But then you perform two operations, one of which is unnecessary. I presume that Even if it doesn't, you have to perform another (unnecessary) null check. Then I could argue that Alright, this was a bit beside the point, which was that not considering this case of @munificent Well, in the end, this problem can easily be mitigated by a very simple class like class Absent<T> {
T? get value;
bool get isAbsent;
} where |
For the record, if I was to design |
Currently Dart maps return
null
when a lookup fails. With null safety, that meansoperator[]
always returns a nullable type. That can be annoying.Consider if
Map
had three type parameters:K
,V
andD
whereD
is the type of the default value returned when a lookup fails.It would be
Map<K, V extends D, D>
, andoperator[]
has return typeD
.To avoid breaking everyone we could introduce a new
Map
type,XMap
(probably not), and have all currentMap<K, V>
instances implementXMap<K, V, V?>
.Then we can have
XMap
constructors taking a default value, rather than just always usingnull
as the default value.Map literals could write
{"x": 1, "y": 2, default: -1}
to create anXMap
.Obviously we'd want to rename
XMap
toMap
soon enough, but without breaking code which only knows the oldMap
. That could be based on language version, and maybe type aliases.Old code sees
typedef Map<K, V> = real.Map<K, V, V?>;
, new code sees the realMap
directly.(Maybe they'll want a some short type aliases too, like
typedef map<K, V> = Map<K, V, V>;
)The text was updated successfully, but these errors were encountered: