alavrik / erlson

Erlang Simple Object Notation - dynamic name-value dictionary data type and syntax for Erlang
MIT License
81 stars 17 forks source link

Add get_value/2 and get_value/3. #8

Closed ewanmellor closed 11 years ago

ewanmellor commented 11 years ago

These work the same as proplists:get_value but should be faster because they use the fact that the dictionary is ordered.

alavrik commented 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.

ewanmellor commented 11 years ago

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).
alavrik commented 11 years ago

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.

ewanmellor commented 11 years ago

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.

alavrik commented 11 years ago

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.

alavrik commented 11 years ago

@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!