docopt.nim icon indicating copy to clipboard operation
docopt.nim copied to clipboard

If an argument is missing, it's value is "nil" (a string), not nil (the real nil).

Open moigagoo opened this issue 7 years ago • 10 comments

I have an isNil check in my code that used to work with the older version. Now it breaks because isNil is false due to the value being "nil," not nil.

moigagoo avatar Oct 04 '16 10:10 moigagoo

Please clarify (give an example that fails).

oprypin avatar Oct 04 '16 10:10 oprypin

Consider the following simple example:

import docopt

const doc = """
Foo.

Usage:
  doco do [--param=<some-param>]
  doco (-h | --help)
  doco --version

Options:
  -h --help                         Show this screen.
  -v --version                      Show version.
  -p --param=<some-param>           Some param without default value.
"""

let args = docopt(doc, version = "0.1.0")

if args["do"]:
  let param = $args["--param"] # expected to be nil if not passed

  echo param.isNil
  echo param == "nil"

Compile and run it:

$ doco do
false
true

$ doco do -p foo
false
false

As you can see, if --param is not provided, its value is "nil" the string, not nil the default string value.

moigagoo avatar Oct 04 '16 10:10 moigagoo

You are converting the value to string using $ and then wondering why it's a string?

oprypin avatar Oct 04 '16 10:10 oprypin

Terribly sorry. What a stupid mistake...

moigagoo avatar Oct 04 '16 10:10 moigagoo

@BlaXpirit Still, it's a bit weird that $ applied to vkNone value produces a non-empty string, don't you think? nil is a valid value for string type, and it feels like a good reflection of vkNone.

I'm asking for two reasons:

  • it used to work this way; isNil did return true in this situation
  • in order to check if a param was passed, I have to check if its kind is vkNone, which means I have to import docopt whenever I need to perform such a check.

moigagoo avatar Oct 04 '16 10:10 moigagoo

I am sure that applying $ to a Value never returned nil and I don't think this is a good idea, because generally $ always returns a string.

Nim's shenanigans with imports and availability of methods is a whole another topic...

oprypin avatar Oct 04 '16 10:10 oprypin

I'm sorry, it seems like I am incorrect, and $nil returns actual nil in Nim.

oprypin avatar Oct 04 '16 10:10 oprypin

@BlaXpirit So, do you too think that $ applied to vkNone should return nil? IMHO it makes perfect sense.

moigagoo avatar Oct 04 '16 12:10 moigagoo

@BlaXpirit

generally $ always returns a string.

There's no contradiction with my proposal. nil is a string.

moigagoo avatar Oct 04 '16 12:10 moigagoo

Here's another example of what looks like a problem. The following script:

let doc = """
A test program
Usage:
  test [CONFIG]

Options:
  CONFIG        Path to configuration file
"""
import strutils
import docopt

let args = docopt(doc, version = "Test 0.1.0")
echo args
let no_config = ($args["CONFIG"]).isNil
echo no_config

Compiles without errors on Nim 0.16.0 (Ubuntu 16.04, x86_64).

When the compiled program is run with no arguments:

$ ./test
{CONFIG: nil}
false

When run with an argument:

$ ./test foo
{CONFIG: foo}
false

When run with the argument nil (a string which just happens to be nil):

$ ./test nil
{CONFIG: nil}
false

So how do we test for args["CONFIG"] being nil, as distinct from the string "nil"?

You could sort this out by providing a proc isNil*(v: Value): bool which returns false except for kinds vkStr and vkList, and returns true for those kinds only when the corresponding field is actually nil.

vsajip avatar Jan 11 '17 00:01 vsajip