certik / yaml-cpp

Automatically exported from code.google.com/p/yaml-cpp
MIT License
0 stars 0 forks source link

conversion exception with bool->int #209

Closed GoogleCodeExporter closed 9 years ago

GoogleCodeExporter commented 9 years ago
What steps will reproduce the problem?
1. use node.as<int>() on a boolean node (e.g. true or false)

What is the expected output? What do you see instead?

an integer with the value of 1 or 0 is expected, instead, a bad conversion 
exception is raised

What version of the product are you using? On what operating system?
0.5.1

Original issue reported on code.google.com by nev...@gmail.com on 10 Jun 2013 at 8:18

GoogleCodeExporter commented 9 years ago
"true" isn't a valid integer value. See 
http://www.yaml.org/spec/1.2/spec.html#id2803828

If you want to convert it to 0 or 1, then

int x = node.as<bool>();

should work fine.

Original comment by jbe...@gmail.com on 10 Jun 2013 at 8:24

GoogleCodeExporter commented 9 years ago
as implies conversion operation... find me a language that doesn't support 
casting a boolean to an integer, it's ubiquitous.

My specific problem is I'm using it with a parameter that most of the time is a 
boolean but has additional functionality when using integer values.  So reading 
it as an int covers all cases.

Original comment by nev...@gmail.com on 10 Jun 2013 at 9:53

GoogleCodeExporter commented 9 years ago
I can find you a language that does this - YAML :)

In any case, you could try to parse it as an integer, and if it fails, parse it 
as a boolean.

Original comment by jbe...@gmail.com on 10 Jun 2013 at 10:04

GoogleCodeExporter commented 9 years ago
The yaml spec says nothing about converting values from one to another, it 
lists out grammar and parser rules just like any other language but doesn't 
touch on things only a compiler would worry about.  The is a method is at that 
level, no?  This is where the conversion to other types would happen in the 
plugin api as well, right?

It is overly restrictive to not support casts between integer/boolean when the 
scalar type is the other case, and you don't break any standards by doing so.

I hope you'll consider changing it...

Original comment by nev...@gmail.com on 10 Jun 2013 at 10:21

GoogleCodeExporter commented 9 years ago
As far as I can tell, what you're proposing is pretty far-reaching and 
difficult. You want yaml-cpp to be able to detect "conversion chains", e.g.:

node.as<X>();

should determine if there is a conversion route from the "intrinsic" type of 
the node to X, and then convert it accordingly. Should floats be truncated to 
int? Signed be converted to unsigned? Etc...

Are there any other YAML parsers that handle this the way you're suggesting? As 
far as I can tell, all of the ones in dynamically-typed languages simply 
auto-type it and then rely on language features to cast to your heart's 
content. In C++, I can't rely on auto-typing :)

Original comment by jbe...@gmail.com on 10 Jun 2013 at 10:28

GoogleCodeExporter commented 9 years ago
Yes most implementations rely on duck-typing but you obviously don't have the 
luxury of duck-typing built in to c++... but this is some of what Node 
addresses.  Yes I don't know where the line should be drawn for floats 
truncated to int but again the boolean/int stuff is ubiquitous.  snakeyaml also 
uses first class numeric types which all have conversion methods defined so in 
some senses yaml-cpp falls into a class of it's own, distinct from the spartan 
libyaml (which itself was developed for use with python).  All implementations 
except for libyaml would support a one liner that handles my use case fairly 
cleanly and involve a cast operation/method... but with what you propose I 
should query the type or catch exceptions and retry, both are longer and 
unsavory.

Because node is your "any" type container, it's where the operations have to be 
defined if convenience as approachable as that of other implementations, even 
if some of the fault of that lies with language design choices. 

Original comment by nev...@gmail.com on 10 Jun 2013 at 10:53

GoogleCodeExporter commented 9 years ago
Do you have a link to snakeyaml's implementation of this behavior?

Original comment by jbe...@gmail.com on 10 Jun 2013 at 11:22

GoogleCodeExporter commented 9 years ago
You may have miss-understood, snakeyaml uses first class numeric types, like 
Integer as opposed to int, all of these have methods for converting from one 
type to another at run time (e.g. "explicit" duck-typing?). 
http://docs.oracle.com/javase/6/docs/api/java/lang/Number.html

You may point out that Boolean doesn't implement Number, this is because java 
at it's lowest levels doesn't consider boolean types as an integral type and so 
no conversions are allowed on that specific type, so you must use if/switch 
statements to work with it (this is not true of other types though).  In c++ 
bool is an integral type, however: 
http://en.cppreference.com/w/cpp/types/is_integral

Original comment by nev...@gmail.com on 10 Jun 2013 at 11:53

GoogleCodeExporter commented 9 years ago
Hmm; it sounds like you're saying that snakeyaml is another implementation that 
doesn't make this a one-liner. Is that correct? Do you know of any 
implementation in a statically-typed language that makes this a one-liner?

Original comment by jbe...@gmail.com on 11 Jun 2013 at 9:28

GoogleCodeExporter commented 9 years ago
Yes you are right that it doesn't make it because the language itself doesn't 
consider bools as an integral type at all (a controversial and unsettled 
philosophy) and most implementations of yaml are with languages are more 
duck-typing (ruby (pure? syck?), python (libyaml), matlab (snakeyaml)).  If you 
want to take the example of float/long/short casting, it is a one liner with 
snakeyaml but boolean is an edge case in java.  So I'm wrong on statically 
typed languages supporting a one liner boolean casting to int by this caveat.

C# has the same philosophy on bools as not an integral type as well but allows 
runtime conversion from static types, including strings, as well as Objects to 
ints through the System.Convert class, which allows for a one liner.  The .net 
offerings for yaml are less mature however, but do not depend on syck or 
libyaml. yamldotnet leaves YAML scalars as strings for the user to work with 
where as yaml .net parser (a student project) relies completely on runtime 
querying of type and casting to the appropriate Node specialization class 
before accessing the contents.  As far as I can tell there these are noticeably 
less rich implementations than yaml-cpp.

haskell's implementations are pretty much just parsers, one the reference 
parser, another is an event based implementation (like sax), and the last I 
found is a syck based implementation which again leaves scalars as strings as 
far as I can tell.  ocaml's implmementation also uses syck.

So I can't show you a statically typed implementation in a static language that 
does allow a one linear but I hope you see it's just because of some details 
and immature implementations.  Had snakeyaml been in c# it'd be there, and java 
derivative languages follow suite with the boolean is not integral philosophy.

Coming back from that though you have Node behaving as a container taking care 
of all casting/converting... but through this exercise I fully realize you 
completely rely on the user and the conversion api to really get at scalar 
types, which are internally just strings.  You do not do keep type info on hand 
for what a scalar actually parses to (can be done with or without RTTI just the 
same as you've done with map, seq, scalar, null).  Actually this would probably 
speed you up since you wouldn't be allocating so many stringstreams... but more 
on topic I can understand better why would refrain from the support as you must 
put a boolean parser with an int parser which definitely looks ugly.  Still, at 
the high level it's nonsensical behavior.

At this point I give in, I feel I make a good point but it would involve large 
or ugly changes to yaml-cpp to do well.

Original comment by nev...@gmail.com on 11 Jun 2013 at 11:50