[erlang-questions] distinguish proplists vs. lists of proplists
Fred Hebert
mononcqc@REDACTED
Wed Sep 16 16:19:40 CEST 2015
On 09/16, Richard A. O'Keefe wrote:
>Does anyone know *why* the proplists module is so tolerant of
>junk in proplists? Is it because
>
>get_value(Key, [{Key,Val}|_], _) -> Val;
>get_value(Key, [Key|_], _) -> true;
>get_value(Key, [_|Ps], Default) -> get_value(Key, Ps, Default);
>get_value(Key, [], Default) -> Default.
>
>is the easiest thing to write, or is there a use case for it?
>
That simpler implementation wouldn't work to properly respect current
type signatures or the currently (partly broken) behaviour.
The reason is that it suffers from the fact that I could describe a
property's key as {body, weight}, and {body, height}, or maybe full
records could be used as keys currently (although they should not)
Now the problem is obviously that having only a key has the implicit
meaning of {Key, true}, and expansion has to be done dynamically.
By virtue of having generic keys, proplists in your version should
semantically be able to consider `{body, weight}' as either a key/value
pair (where key=body, value=weight), or as a tuple-key that has the
value 'true' depending on the specific call and context. That again is
kind of fine and I would expect makes sense, but the type specifications
maintain that only tuples or atoms are accepted, which yields the
following funny result:
1> Proplist = [{{body, height}, 172}, {body, lives}, attribute].
[{{body,height},172},{body,lives},attribute]
2> proplists:get_value({body, height}, Proplist).
172
3> proplists:get_value(attribute, Proplist).
true
4> proplists:get_value({body,lives}, Proplist).
undefined
The actual one instead goes for a bit of a more complex logic making
assertions on keys being atoms or tuples:
https://github.com/erlang/otp/blob/maint/lib/stdlib/src/proplists.erl#L226-L241
The surprising behaviour is possibly due to checks being too lax, where
tuples are valid keys only in part under the current implementation, and
they should probably not be (alternatively, they are too strict compared
to the current type signatures).
The type signatures of proplists and their implementation would probably
be due an update so that the type:
property() = atom() | tuple()
is instead:
key() :: atom()
property() :: key() | {key(), term()}
Currently, though, the proplists module is kind of victim of its own lax
implementation and an overly permissive spec, given most of the function
in the proplists module don't even expect the list passed in to even
contain property() as a type -- only normalize/2 and property/1 put such
restrictions.
I mean, even property/2 has the documented type signature:
property(Key, Value) -> Property
Types:
Key = Value = term()
Property = atom() | {term(), term()}
Where the function to create properties does not even enforce creating
actual properties defined within the module.
More information about the erlang-questions
mailing list