Hello,
when I use the Resource Finder (RF) to check the value of a command line option, the RF cannot parse an input string (using .asString()) if it is composed of numbers only. (i.e. myfile.exe --option 123 does not parse "123" as string using .asString()).
The problem is not caused by the parsing of yarp::os::Value to std::string or yarp::os::ConstString, see the code below.
#include <iostream>
#include <yarp/os/Network.h> // for yarp network
#include <yarp/os/ResourceFinder.h>
int main(int argc, char * argv[])
{
// Definition and configuration or ResourceFinder
yarp::os::ResourceFinder &rf = yarp::os::ResourceFinder::getResourceFinderSingleton();
rf.configure(argc, argv);
// Getting a string from command line option --name
yarp::os::ConstString name = rf.check("name", yarp::os::Value("default-name")).asString();
std::cout << "The name is: " << name << std::endl;
// Parsing and printing yarp::os::Value to ConstString and std::string
yarp::os::Value value = yarp::os::Value("123");
yarp::os::ConstString const_string = value.asString();
std::string std_string = value.asString();
std::cout << "The ConstString value is : " << const_string << std::endl;
std::cout << "The std::string value is : " << std_string << std::endl;
return 0;
}
when I run the command myfile.exe --name 123
I get the following output:
The name is:
The ConstString value is : 123
The std::string value is : 123
Hi @miccol,
ResourceFinder::check(...) checks if there exists a property of the given name.
See documentation here:
http://www.yarp.it/classyarp_1_1os_1_1ResourceFinder.html#afd52aea1d054524d8c4ebefc458978b4
Hi @Nicogene , I meant this http://www.yarp.it/classyarp_1_1os_1_1Searchable.html#ac688a1760e6ff5b39ceec9e3a13bc1f0
The usage is the one commonly found in YARP example, as here:
http://wiki.icub.org/wiki/Summary_of_iCub_Software_Development_Guidelines
Sorry I didn't see the second argument in check..
In my opinion I don't like that calling the same function with one, or more parameter you have different behaviour and output.
check() should check that for that key the value exists, not return the value, there is find() for that.
I find this thing very misleading, but maybe it is a personal taste.
BTW I will check why it can't parse number input, thanks for reporting!
I totally agree! the name is misleading and I prefer find too. However, I cannot find a way to define a default value using find directly (as done for check).
check is the service devoted to deal with options that are present or not provided.
In case they're not provided, you can ask for default values instead, using the second parameter.
For me, check is a better solution than find, if you consider that you cannot find an option that is not there ๐
Just a reminder for me, also happening with '123' and "123"
@miccol if you replace this
yarp::os::ConstString name = rf.check("name", yarp::os::Value("default-name")).asString();
with this
yarp::os::ConstString name = rf.check("name", yarp::os::Value("default-name")).toString();
it works
@miccol if you replace this
yarp::os::ConstString name = rf.check("name", yarp::os::Value("default-name")).asString();
with this
yarp::os::ConstString name = rf.check("name", yarp::os::Value("default-name")).toString();
it works
I'm a bit confused by this behaviour.
The question now is: why, _in this particular working condition_ (e.g. input: --name 123), asString and toString provide two different results?
toString calls for the string representation of the Value, so it sort of forces to transform an object into a string. Any content can be dumped as a string, hence it will always work, regardless whether the value is a string, an integer, a double, a bool, or a list.asString asks to return a Value as a string, but if the original value is not a string then I believe the outcome will be kind of unpredictable, or at least different from what expected.isString returns true if the value is actually a string, false otherwise.--name 123 is interpreted as an integer, I think, thus asString doesn't work.
Thereby, try out --name "123".
"" '' seems to be ignored:
--name "123"--> my name is--name '123'--> my name is--name 'ciao'--> my name is ciaoProbably in rf.configure(argc, argv)
When I aim to pass on a list as command line option, I usually do:
--name "(item_0 item_1 ...)"
and calling from the code
Bottle *list=rf.find("name").asList();
works. Therefore, somehow there must be cases where "..." are well interpreted inside rf.configure().
That said, however, out of curiosity, why would one pass on a sheer integer as a string?
When you call the is* methods, that's the outcome:
| | input | isInt() | isString() | isList() |
| ---: | :---: | :---: | :---: | :---: |
| 1 | abc | โ | โ๏ธ | โ |
| 2 | "abc" | โ | โ๏ธ | โ |
| 3 | 123 | โ๏ธ | โ | โ |
| ๐ 4 | "123" | โ๏ธ | โ | โ |
| 5 | "a b 1" | โ | โ๏ธ | โ |
| ๐ 6 | "(a b 1)" | โ | โ | โ๏ธ |
Thereby, it seems that the ResourceFinder makes some assumptions while parsing the input options. As a result, this behavior isn't necessarily to be considered buggy.
In particular, line 6 is the only viable (hence required) solution to pass on a list through the command line. Thus, I tend to think of line 4 as a natural extension.
So do we all agree that it is not a bug but an intended implementation? Shall we close this issue?
If it is intentional, then should the same behavior be implemented in the code below?
yarp::os::Value value = yarp::os::Value("123");
yarp::os::ConstString const_string = value.asString();
std::string std_string = value.asString();
My point was only to highlight the fact that there must something else going on inside ResourceFinder with respect to Value since it has to parse a more complex input that has to do with the command line options.
However, let me add another twist to the mystery.
Look at here: https://github.com/robotology/icub-main/blob/master/src/tools/controlBoardDumper/main.cpp#L935-L940
rf.setDefault("part","head");
rf.setDefault("robot","icub");
rf.setDefault("rate","500");
rf.setDefault("joints","(0)");
rf.setDefault("dataToDump","(getEncoders getEncoderSpeeds getEncoderAccelerations getPositionErrors getOutputs getCurrents getTorques getTorqueErrors)");
rf.configure(argc,argv);
Apparently, the method setDefault() correctly works out a string containing a plain number.
Can anyone extend the test with the use of setDefault()?
@miccol I would change the way RF operates rather than changing the behavior of Value.
Even if we're dealing with a quite significant corner case here, RF can return "123", "123.4" as strings rather than as numbers.
I would better change the user code in order to make it foresee inputs as numbers and then change them internally to strings by means of the C++11 routine to_string().
If it is intentional, then should the same behavior be implemented in the code below?
yarp::os::Value value = yarp::os::Value("123");
yarp::os::ConstString const_string = value.asString();
std::string std_string = value.asString();
That is not a fair comparison, because adding the quotes "" you are forcing it to be a string right _before_ calling Value.
The correct comparison is
yarp::os::Value value = yarp::os::Value(123); without quotes. This is handled the same way.
The point is that there is no equivalent to
yarp::os::Value value = yarp::os::Value("123"); from commad line.
When data are read from command line, they are always a string, so 123 and "123" are actually both a char[] like in main(int argc, char *argv[]).
This makes it impossible to distinguish between the _intended_ usage two.
Everything is a string, so when parsing command line a choise has to be made about the representation to use. _I think the underlying assumption is that when the user write a number, it means a number_, so it is treated accordingly, which is reasonable to me.
If you need to get the string out of it, you can call the "toString()" method. It may be not so straightforward in your case, but I think that's is the correct way to proceed.
I think that @barbalberto got the point, it has been a very useful discussion but for me we can close this issue, do you agree?
FIne for me. Thanks @barbalberto !
Most helpful comment
That is not a fair comparison, because adding the quotes
""you are forcing it to be a string right _before_ callingValue.The correct comparison is
yarp::os::Value value = yarp::os::Value(123);without quotes. This is handled the same way.The point is that there is no equivalent to
yarp::os::Value value = yarp::os::Value("123");from commad line.When data are read from command line, they are always a string, so
123and"123"are actually both achar[]like inmain(int argc, char *argv[]).This makes it impossible to distinguish between the _intended_ usage two.
Everything is a string, so when parsing command line a choise has to be made about the representation to use. _I think the underlying assumption is that when the user write a number, it means a number_, so it is treated accordingly, which is reasonable to me.
If you need to get the string out of it, you can call the "toString()" method. It may be not so straightforward in your case, but I think that's is the correct way to proceed.