ramda: R.propOr not as useful as lodash's _.result; should it throw if object is undefined?

This is nice in lodash:-

    var people = [
        {
            name: "Dave",
            age: 30
        },
        {
            name: "Anne",
            age: 28
        },
    ];

    _.result(_.find(people, function (person) {
        return person.age === 40;
    }), "name", undefined);

Depending on the result of the person.age === N test, either the name of the person or undefined will be returned.

The Ramda equivalent using propOr (is there a better way?) isn’t useful:-

    R.propOr(undefined, "name", R.find(R.propEq('age', 40))(people));

This throws with “Uncaught TypeError: Cannot convert undefined or null to object”.

What makes the lodash function work is the fact that _.result can cope with the result of the find being undefined (or null). R.propOr can’t cope with this. I think that it (and similar functions) should be able to cope with undefineds and nulls - especially since the result of many list functions (returning undefined) might well be piped into them.

(Yes, I’ve got the first two args to R.propOr the right way round. The documentation has it wrong; I’ve raised a separate issue about that.)

About this issue

  • Original URL
  • State: closed
  • Created 9 years ago
  • Comments: 18 (11 by maintainers)

Most upvoted comments

One of the fundamental tenets of functional programming and in Ramda is the composition of functions in a pipeline. Therefore the behavior of a function like propOr wrt an undefined object should not be considered in isolation, but rather as part of Ramda’s whole notion of function pipelining. After all, as an API user I’m not going to write this:-

var result = R.propOr('n/a', 'name', undefined);

Since many Ramda functions can return undefined, it then follows that, for the sake of pipelining, every function that a) takes a data arg (or args) and b) might reasonably be part of a pipeline, needs to have a story in the code and in the documentation for what happens if that arg gets piped in as undefined or null.

The worst thing is to have no story. Then the API user has to experiment to see what happens (or get bitten unexpectedly later on), and the likelihood of a good thing happening is low. And if a good thing happens, can it be relied upon since there’s no documentation?

A better thing, but still pretty bad, is to have a story and that story is: “throws an exception if the arg is specified as undefined or null”. At least we know where we are, but throwing exceptions is awful because they break the pipeline.

The best thing (in fact the only good thing) is to have a story and that story is aimed at not throwing an exception, but rather to aid pipelining. So in the case of propOr, and to answer your question, the correct result of

propOr(value, name, refToNothing)

is value. This even fits the current description of the function:-

If the given object has an own property with the specified name, returns the
value of that property. Otherwise returns the provided default value.

Although it would be nice to augment this description with:-

If the given object is undefined or null, the default value is returned.

I have experience of another API that supports method chaining where thought was not given to the fact that args could well be null (which caused the API to throw). These kinds of APIs are not nice to work with.

Now, to be clear, I’m not asking for an isolated change to the behavior of propOr. I’m talking about a considered review of each and every function in Ramda, wrt adding that nice story I talked about, in the code and in the documentation, for the data param(s) on the right of the param list. Such a thing would really make Ramda useful and usable, and fits right in with your own stated philosophy of:-

We try to make it clear what our functions do, to ensure there are no surprises.