ArduinoJson icon indicating copy to clipboard operation
ArduinoJson copied to clipboard

Comparison operators for custom types

Open MoonModules opened this issue 1 year ago • 5 comments

Description

  1. The program uses ArduinoJson 6
  2. The issue happens at compile time
  3. The error is not in the list

See reproduction code below. Using a custom defined struct works for assignments (using Converter<>) as described in https://arduinojson.org/news/2021/05/04/version-6-18-0/

But I cannot get it to work for comparison operators (like var["value"] != value in below example).

I get this error: .pio/libdeps/esp32dev/ArduinoJson/src/ArduinoJson/Variant/VariantCompare.hpp:203:15: error: 'ArduinoJson::V6214PB2::detail::Comparer<Coordinate, void> comparer' has incomplete type Comparer<T> comparer(rhs);

Tried to add Comparer like functions but all resulted in compile errors.

Help / code example really appreciated.

Thx Ewoud

Troubleshooter's report

  1. The program uses ArduinoJson 6
  2. The issue happens at compile time
  3. The error is not in the list

Environment

  • Microcontroller: ESP32
  • Core/Framework: Expressif 3.20014.0
  • IDE: VSCode 1.85 PIO v3.3.2

Reproduction code


This code:

template <typename Type>
JsonObject setValue(const char * id, Type value) {
  JsonObject var = findVar(id);
  if (var["value"].isNull() || var["value"] != value) {
    var["value"] = value;
  }
}

works for:

mdl->setValue<int>("var1", 10);

but not for:

Coordinate xyz;
xyz.x = 1;
xyz.y = 2; 
xyz.z = 3;
mdl->setValue<Coordinate>("var2", xyz, 0);

This code is present:

template <>
struct Converter<Coordinate> {
  static bool toJson(const Coordinate& src, JsonVariant dst) {
    dst["x"] = src.x;
    dst["y"] = src.y;
    dst["z"] = src.z;
    return true;
  }

  static Coordinate fromJson(JsonVariantConst src) {
    return Coordinate{src["x"], src["y"], src["z"]};
  }

  static bool checkJson(JsonVariantConst src) {
    return src["x"].is<int>() && src["y"].is<int>() && src["z"].is<int>();
  }
};



MoonModules avatar Jan 15 '24 20:01 MoonModules

Hi @MoonModules,

Comparison with custom types is not supported. As a workaround you can do var["value"].as<Coordinate>() != value.

Best regards, Benoit

bblanchon avatar Jan 16 '24 19:01 bblanchon

Hi Benoit, Thx for your reply.

Even better (as the function is a template):

JsonObject setValue(const char * id, Type value) {
  JsonObject var = findVar(id);
  if (var["value"].isNull() || var["value"].as<Type>() != value) {
    var["value"] = value;
  }
}

but then != was not defined for Coordinate so I changed the struct:

struct Coordinate {
  uint16_t x;
  uint16_t y;
  uint16_t z;
  bool operator!=(Coordinate par) {
    return x != par.x || y != par.y || z != par.z;
  }
};

And now it's perfect !

One question, is comparison with custom types not supported by design (as it should be done as shown above), or might it be a future enhancement?

Thx again,

Kind regards,

Ewoud from MoonModules

MoonModules avatar Jan 17 '24 17:01 MoonModules

Only thing I am not sure of is if the Type is const char * then the != should be a strcmp ... could that also be overloaded (question to myself 🙂 )

In that case lot less strcmp in code which looks cleaner (but could confuse core char * people 🙂)

ewoudwijma avatar Jan 17 '24 20:01 ewoudwijma

JsonString ... 🙂

ewoudwijma avatar Jan 18 '24 07:01 ewoudwijma

@MoonModules, I suppose we could make this a feature, but as a wise man once wrote:

Features have a specification cost, a design cost, and a development cost. There is a testing cost and a reliability cost. The more features there are, the more likely one will develop problems or will interact badly with another. [...] Features have a documentation cost. Every feature adds pages to the manual, increasing training costs. Features that offer value to a minority of users impose a cost on all users.

It'll convert this issue to a feature request and see if more users are interested.

bblanchon avatar Jan 18 '24 09:01 bblanchon