Closed ewanmellor closed 11 years ago
I don't know about your use case, but I found that it is usually more convenient to define get_value
as a macro like this:
-define(get_value(X, Default),
try X
catch error:'erlson_not_found' ->
Default
end
).
-define(get_value(X), ?get_value(X, 'undefined')).
This way, you can use get_value
with Erlson syntax. For example:
?get_value(X.foo.bar),
?get_value(X.foo.bar, 1)
As for the functional interface for accessing nested fields, I'm still feeling reluctant about adding it. There are at least two different behaviors one can choose depending on a particular use case:
Your addition (and my macro) implements the second behavior but I'm not sure it is a good default for a library function.
I was thinking about the case where the key is a variable, so you can't use the dot syntax:
Received = erlson:from_proplist([{foo, bar}, {baz, buzz}]),
lists:map(fun (K) -> erlson:get_value(K, Received) end, [foo, baz]).
In that case, you couldn't write Received.K
.
I like the idea of a macro for the three-arg case -- I hadn't thought of that. Maybe if you gave them more descriptive names, it wouldn't seem too bad having them in a library header, and you could support both cases:
?get_value_def_leaf(X.foo.bar, 1).
?get_value_def_any(X.foo.bar, 1).
I would really like to avoid implementing any field access functions as a part of the Erlson library. Erlson has always been more about syntax rather than comprehensive features. Besides, as you may know, key-value lookup interfaces is a highly debatable topic in the Erlang community and I wanted to refrain from that.
There are some external libraries that can do that. For example, this one looks pretty good: https://github.com/etrepum/kvc
As for the macro, let me think about better names and I'll add them to the header.
kvc wouldn't be aware that erlson lists are ordered though, would it? That was the only reason for this change in the first place -- to use the fact that the lists are ordered to get a performance boost. Otherwise, I could just use proplists:get_value
.
Good point about optimized access! Let's take another shot at it. With the above macros, your example can be rewritten as
lists:map(fun (K) -> ?get_value(erlson:fetch(K, Received)) end, [foo, baz]).
This would become possible as well:
lists:map(fun (K) -> ?get_value(erlson:fetch(K, Received), Default) end, [foo, baz]).
Hmm... These examples got me thinking about adding both: get_value
functions as you suggested and also ?get_value
macros. Let me think a little bit more about details and I'll probably do it in the next couple of days.
@ewanmellor, I decided to merge it "as is" and deal with everything else separately. Distinguishing between missing leafs and missing sub-trees at Erlson syntax level is not as simple as I thought. It will take some extra work.
Also, I will add the macros shortly and update the documentation a little bit later.
Thank you for the contribution!
These work the same as proplists:get_value but should be faster because they use the fact that the dictionary is ordered.