docopt.cpp: isLong() does not work as it is expected

Although asLong() returns a valid value for an integral value passed as an argument isLong() at the same time returns false.

It looks like such behaviour is connected with the correction #28: meaning of asLong() was changed but isLong() left unchanged.

In my particular case, there was a check if the passed value is a number (isLong()?): to have a guarantee that there will be no exception from asLong(). However, the check returned false on every occasion.

About this issue

  • Original URL
  • State: open
  • Created 8 years ago
  • Reactions: 1
  • Comments: 16 (12 by maintainers)

Most upvoted comments

Yeh, I’m not 100% happy with the ‘value’ class.

I like your idea about the forms with default values. I think that makes a lot of sense. And “isEmpty” is a good idea as well.

isLong could return true if and only if the call to asLong will succeed.

I too assumed that isLong() would just tell me whether asLong() was going to throw an exception. I feel like the entire value API is a bit weird actually.

Since the docopt description string is untyped there’s no way for docopt to know whether the arguments should be strings or not until the user (of docopt) tries to use the values. So it’s weird that the docopt::values have a preconceived idea of whether they are a bool, long, string or whatever. They can’t possibly know that until they are queried. A more sane API would be something like this:

class value : public std::string
{
public:
    bool isInt() const; // Returns true if it can be converted to an integer successfully.
    int toInt(int def = -1) const; // Convert to int, or return `def` on failure.
    bool isBool() const; // Return true if it is "true" or "false"
    bool toBool(bool def = false) const; // etc.

    // And if you *insist* on using exceptions, remove the `= -1` and `= false` above and add:
    int toInt() const; // Convert to int, throw exception on failure.
    bool toBool() const; // Convert to bool, throw exception on failure.
};

That is way simpler and more obvious I think. However you may wish to wait for C++17 to be common and then it can be done properly: std::optional<int> toInt();