[erlang-questions] distinguish proplists vs. lists of proplists

Fred Hebert <>
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