Search code examples
c++yaml-cpp

Unexpected results for yaml-cpp comparisons


Consider the following code (yamltest.cpp):

#include <yaml-cpp/yaml.h>
#include <iostream>
#include <string>

int main() {
  std::string val = "[1, 2, 3]";
  YAML::Node yn0 = YAML::Load(val);
  YAML::Node yn1 = YAML::Load(val);

  std::cout << "===== yn0 =====\n" << yn0 << std::endl;
  std::cout << "\n"  << std::endl;
  std::cout << "===== yn1 =====\n\n" << yn1 << std::endl;

  std::cout << std::boolalpha;
  std::cout << "yn0 == yn0: " << (yn0==yn0) << std::endl;
  std::cout << "yn1 == yn1: " << (yn1==yn1) << std::endl;

  std::cout << "yn0 == yn1: " << (yn0==yn1) << std::endl;
  std::cout << "yn1 == yn0: " << (yn1==yn0) << std::endl;
  std::cout << "YAML::Load(val) == YAML::Load(val): " << (YAML::Load(val)==YAML::Load(val)) << "\n" << std::endl;

  std::cout << "yn0 != yn0: " << (yn0!=yn0) << std::endl;
  std::cout << "yn1 != yn1: " << (yn1!=yn1) << std::endl;

  std::cout << "yn0 != yn1: " << (yn0!=yn1) << std::endl;
  std::cout << "yn1 != yn0: " << (yn1!=yn0) << std::endl;
  std::cout << "YAML::Load(val) != YAML::Load(val): " << (YAML::Load(val)!=YAML::Load(val)) << std::endl;
  std::cout << std::noboolalpha;

  return 0;
}

Along with its associated Makefile:

yt:
    g++ -g -Wall yamltest.cpp -o yt -lyaml-cpp

clean:
    rm yt

Running it produces the following results:

$ ./yt 
===== yn0 =====
[1, 2, 3]


===== yn1 =====
[1, 2, 3]

yn0 == yn0: true
yn1 == yn1: true
yn0 == yn1: false
yn1 == yn0: false
YAML::Load(val) == YAML::Load(val): false

yn0 != yn0: false
yn1 != yn1: false
yn0 != yn1: false
yn1 != yn0: false
YAML::Load(val) != YAML::Load(val): false

I expected all of the == tests to return true and all of the != tests to return false, but this is clearly not happening. So, is this the correct way to compare YAML-CPP objects to test for equivalence? If not, what is the correct way?

This is running on CentOS 7.x and GCC 9.2.0.


Solution

  • Looking into the code, the operator== is testing for identity and not for equality.

    bool YAML::detail::node::is(const node& rhs) const { return m_pRef == rhs.m_pRef; }
    

    Therefore, the operator== will return true only if the objects are the same and not if they contain the same value.

    For the operator!= case, it is a bug (IMHO), the Node is implicitly converted to bool type with value unspecified_bool::true_value. Therefore, the expressions are always false.

    Googling a bit, there are open enhancement request for your use case and some code contributed to compare for equivalence.