# nlohmann::json and VTK's public API

**URL:** https://discourse.vtk.org/t/nlohmann-json-and-vtks-public-api/15131
**Category:** Development
**Tags:** proposal
**Created:** [January 9, 2025, 4:27pm UTC](https://discourse.vtk.org/t/nlohmann-json-and-vtks-public-api/15131 "2025-01-09T16:27:03Z")
**Posts on this page:** 20
**Page:** 1

<div class="post-metadata">

### Author: ![dcthomp](https://discourse.vtk.org/user_avatar/discourse.vtk.org/dcthomp/32/60_2.png) [@dcthomp](https://discourse.vtk.org/u/dcthomp)
#### Post date: [January 9, 2025, 4:27pm UTC](https://discourse.vtk.org/t/nlohmann-json-and-vtks-public-api/15131/1 "2025-01-09T16:27:03Z")

</div>

## Problem Statement

As [has already been discussed](https://discourse.vtk.org/t/conflict-with-vtknlohmann-and-nlohmann/14977), VTK currently exposes [nlohmann::json](https://github.com/nlohmann/json/) in some of its public API. This works well, but

1. application developers must be aware that if they also link to nlohmann::json it must be the exact same version (even though the library is header-only); and
2. if we ever decide to switch to a different JSON library, it would require a large API change to VTK or supporting two JSON libraries at once (which we have had to deal with for XML).

## Proposal

Our plan is provide a `vtkJSON` class in `VTK::CommonCore` that contains an internal (non-public) instance of an `nlohmann::json` object and some public methods/operators (`.at()`, `[]`, `.contains()`, …) that it forwards to its internal member. Classes that currently use `nlohmann::json` directly will be modified to use `vtkJSON` instead. This will isolate `nlohmann::json` from the public API.

At the same time, we will also provide a “semi-public” API (with no guarantee of stability) to fetch the internal `nlohmann::json` instance from a `vtkJSON` instance. This utility may live in its own module and would introduce a public dependency on `nlohmann::json` as well as `VTK::CommonCore`.

Does anyone have input to provide before we pursue this change?

@jaswantp FYI

---

<div class="post-metadata">

### Author: ![jaswantp](https://discourse.vtk.org/user_avatar/discourse.vtk.org/jaswantp/32/10046_2.png) [@jaswantp](https://discourse.vtk.org/u/jaswantp)
#### Post date: [January 9, 2025, 4:29pm UTC](https://discourse.vtk.org/t/nlohmann-json-and-vtks-public-api/15131/2 "2025-01-09T16:29:57Z")

</div>

@lassoan @dgobbi

---

<div class="post-metadata">

### Author: ![mwestphal](https://discourse.vtk.org/user_avatar/discourse.vtk.org/mwestphal/32/19_2.png) [@mwestphal](https://discourse.vtk.org/u/mwestphal)
#### Post date: [January 9, 2025, 4:31pm UTC](https://discourse.vtk.org/t/nlohmann-json-and-vtks-public-api/15131/3 "2025-01-09T16:31:47Z")

</div>

Any third-party we vendor in should not be visible in the public API, this proposal is a good idea to avoid that.

---

<div class="post-metadata">

### Author: ![dgobbi](https://discourse.vtk.org/user_avatar/discourse.vtk.org/dgobbi/32/18_2.png) [@dgobbi](https://discourse.vtk.org/u/dgobbi)
#### Post date: [January 9, 2025, 7:11pm UTC](https://discourse.vtk.org/t/nlohmann-json-and-vtks-public-api/15131/4 "2025-01-09T19:11:18Z")

</div>

Sounds like the right solution, but I’m curious about whether vtkJSON is going to be a vtkObject or not. Anything that’s a vtkObject (or vtkObjectBase) is always handled as a pointer (or smart pointer) and things like `operator[]` make no sense for such objects. On the other hand, if vtkJSON does not derive from vtkObjectBase, then it can have `operator[]` (and the object and its operator can be wrapped in Python). Also I’m wondering if vtkJSON will contain a `nlohmann::json` object or if it will just contain a pointer to a `nlohmann::json` object.

---

<div class="post-metadata">

### Author: ![Christos\_Tsolakis](https://discourse.vtk.org/user_avatar/discourse.vtk.org/christos_tsolakis/32/2076_2.png) [@Christos\_Tsolakis](https://discourse.vtk.org/u/Christos_Tsolakis)
#### Post date: [January 9, 2025, 8:16pm UTC](https://discourse.vtk.org/t/nlohmann-json-and-vtks-public-api/15131/5 "2025-01-09T20:16:25Z")

</div>

I think it makes sense to no make it a `vtkObject` and get back nicer APIs just like we do with `vtkTuple`.

---

<div class="post-metadata">

### Author: ![dcthomp](https://discourse.vtk.org/user_avatar/discourse.vtk.org/dcthomp/32/60_2.png) [@dcthomp](https://discourse.vtk.org/u/dcthomp)
#### Post date: [January 9, 2025, 8:19pm UTC](https://discourse.vtk.org/t/nlohmann-json-and-vtks-public-api/15131/6 "2025-01-09T20:19:35Z")

</div>

> [@dgobbi](#):
>
> …Also I’m wondering if vtkJSON will contain a `nlohmann::json` object or if it will just contain a pointer to a `nlohmann::json` object.

My inclination is to contain the object itself; if needed, we can make a `vtkJSONRef` that instead holds a reference.

---

<div class="post-metadata">

### Author: ![lassoan](https://discourse.vtk.org/user_avatar/discourse.vtk.org/lassoan/32/50_2.png) [@lassoan](https://discourse.vtk.org/u/lassoan)
#### Post date: [January 9, 2025, 8:58pm UTC](https://discourse.vtk.org/t/nlohmann-json-and-vtks-public-api/15131/7 "2025-01-09T20:58:07Z")

</div>

Thank you, this sounds good to me. It makes sense for VTK to have an object (a proper, Python-wrapped VTK object) similarly to [vtkXMLDataElement](https://vtk.org/doc/nightly/html/classvtkXMLDataElement.html).

I would expect it to have VTK-style interface, for example `myjson->GetProperty(name)`. But in addition to the VTK-style interface it could be OK to add STL-like interface as well, for convenience when using in C++.

We should avoid any nlohmann-specific, nlohmann-style API, because eventually we will probably have to switch to rapidjson in performance-critical parts of the code (its API is a pain, but it is about 10 times faster) and would be nice if we could still use the same API.

For future-proofing and avoid even VTK-internal dependencies to a specific JSON toolkit, it could make sense to specify an abstract `vtkJSON` class. This class could also contain some helper functions that are common across all JSON implementations. For now, we can do without this separate interface class, but at least make sure to declare all public methods as virtual to make it possible for VTK-based projects to add faster alternative implementations.

* * *

If this will not be a proper VTK object (and will not be Python-wrapped) then this class is basically just an internal VTK implementation detail. A good solution to fix the nlohmann-json interface leakage, but has no use beyond that, because the object and all methods that use it would be inaccessible from Python. Nowadays in most of our projects high-level logic is implemented in Python or at least all objects have to be accessible from Python for debugging and testing, we cannot rely on any non-Python-wrappable C++ code.

In this case, it would be better to remove the `vtk` prefix to avoid any confusion (and allow using `vtkJSON` in the future for a proper VTK object).

---

<div class="post-metadata">

### Author: ![ben.boeckel](https://discourse.vtk.org/letter_avatar_proxy/v4/letter/b/ea5d25/32.png) [@ben.boeckel](https://discourse.vtk.org/u/ben.boeckel)
#### Post date: [January 10, 2025, 4:15am UTC](https://discourse.vtk.org/t/nlohmann-json-and-vtks-public-api/15131/8 "2025-01-10T04:15:54Z")

</div>

> [@lassoan](#):
>
> If this will not be a proper VTK object (and will not be Python-wrapped) then this class is basically just an internal VTK implementation detail.

Note that wrappers might be able to do marshalling to more language-ergonomic representations (e.g., taking/returning a Python dictionary). I don’t think automatic wrapping would get anything useful enough to offset the `vtkObjectBase` drawbacks.

> `vtkObject` or not

I don’t think `vtkObject` makes sense because it should probably just have value semantics rather than the refcounted-reference semantics basically required by `vtkObject`.

> [@dcthomp](#):
>
> My inclination is to contain the object itself; if needed, we can make a `vtkJSONRef` that instead holds a reference.

My head hurts when I try to think about how this would get misused (i.e., it would only ever work as a local variable because as a member “who owns the actual thing” sounds like a nightmare to reason about). But I also don’t think that only supporting `bigobj[innerbigobj]` as a full copy of the inner object makes sense either. This will need documentation, probably along the lines of “use `auto` when storing lookups, `vtkJson` in objects, and use `vtkJsonRef` at API boundaries” or something.

---

<div class="post-metadata">

### Author: ![dcthomp](https://discourse.vtk.org/user_avatar/discourse.vtk.org/dcthomp/32/60_2.png) [@dcthomp](https://discourse.vtk.org/u/dcthomp)
#### Post date: [January 10, 2025, 3:12pm UTC](https://discourse.vtk.org/t/nlohmann-json-and-vtks-public-api/15131/9 "2025-01-10T15:12:44Z")

</div>

> [@ben.boeckel](#):
>
> My head hurts when I try to think about how this would get misused (i.e., it would only ever work as a local variable because as a member “who owns the actual thing” sounds like a nightmare to reason about). But I also don’t think that only supporting `bigobj[innerbigobj]` as a full copy of the inner object makes sense either. This will need documentation, probably along the lines of “use `auto` when storing lookups, `vtkJson` in objects, and use `vtkJsonRef` at API boundaries” or something.

1. My thought was to mitigate this in cases where the JSON data being referenced was owned by a `vtkObject` subclass; we could have `vtkJSONRef` own a reference to the VTK object that owns the JSON data.
2. I agree we would still need to warn developers in cases where JSON data was not owned by a `vtkObject`:

> You are responsible to ensure the underlying JSON object’s lifetime extends beyond that of every `vtkJSONRef` that references it.

---

<div class="post-metadata">

### Author: ![lassoan](https://discourse.vtk.org/user_avatar/discourse.vtk.org/lassoan/32/50_2.png) [@lassoan](https://discourse.vtk.org/u/lassoan)
#### Post date: [January 10, 2025, 3:56pm UTC](https://discourse.vtk.org/t/nlohmann-json-and-vtks-public-api/15131/10 "2025-01-10T15:56:39Z")

</div>

> [@ben.boeckel](#):
>
> I don’t think `vtkObject` makes sense because

vtkObject makes sense, because it is a really useful feature of VTK that 99.5% of objects work the same way (memory management by internal reference counting and many other conventions in naming, etc.). I would expect that the vtkJSON object to work the same way as vtkXMLDataElement: owning the document that it stores.

Having a json object in VTK would be awesome, but if you cannot make it a real vtkObject that follows all VTK conventions (internal reference counting, usual naming conventions, Python-wrapped, own the document inside same way as the XML object, etc.) then don’t make it look like a VTK object, just hide it, make it an internal implementation detail that does not show up anywhere for VTK users.

---

<div class="post-metadata">

### Author: ![dgobbi](https://discourse.vtk.org/user_avatar/discourse.vtk.org/dgobbi/32/18_2.png) [@dgobbi](https://discourse.vtk.org/u/dgobbi)
#### Post date: [January 10, 2025, 4:33pm UTC](https://discourse.vtk.org/t/nlohmann-json-and-vtks-public-api/15131/11 "2025-01-10T16:33:47Z")

</div>

Note that vtkJSON will be wrapped regardless of whether it derives from vtkObject.

[Quote from the python wrapping docs:](https://docs.vtk.org/en/latest/advanced/PythonWrappers.html#other-classes-special-types)

> VTK also uses several classes that aren’t derived from vtkObjectBase. The wrapping of these classes is fully automatic, but is done in a slightly different manner than vtkObjectBase-derived classes. First, these classes have no New() method, and instead the public C++ constructors are wrapped to create an equivalent Python constructor. Second, the Python object contains its own copy of the C++ object, rather than containing just a pointer to the C++ object. The vast majority of these classes are lightweight containers and numerical types.

---

<div class="post-metadata">

### Author: ![dcthomp](https://discourse.vtk.org/user_avatar/discourse.vtk.org/dcthomp/32/60_2.png) [@dcthomp](https://discourse.vtk.org/u/dcthomp)
#### Post date: [January 16, 2025, 5:33pm UTC](https://discourse.vtk.org/t/nlohmann-json-and-vtks-public-api/15131/12 "2025-01-16T17:33:25Z")

</div>

Here is a suggestion on how we might implement vtkJSON. If we add vtkJSONRef at the same time as vtkJSONRef, we can make some of the API function a bit more like `nlohmann::json` (specifically places like the `[]` operator where it could return a reference rather than a value).

```cpp
// SPDX-FileCopyrightText: Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
// SPDX-License-Identifier: BSD-3-Clause
/**
 * @class vtkJSON
 * @brief An object holding parsed JSON data.
 *
 * vtkJSON is a facade for nlohmann::json in order to keep nlohmann::json
 * out of VTK's public API. This will allow us to change the way JSON is
 * represented in VTK without breaking changes to external users.
 *
 * If you must have access to the underlying nlohmann::json object,
 * then use vtkJSONRaw, which is not part of VTK's public API.
 * It is unsupported and subject to change, but will allow you to
 * construct vtkJSON from an nlohmann::json instance, fetch an
 * nlohmann::json instance, and provide other access.
 *
 * Classes in VTK that wish to return JSON data should return
 * vtkJSON instances constructed via vtkJSONRaw's API.
 */

#ifndef vtkJSON_h
#define vtkJSON_h

#include "vtkSmartPointer.h" // For return types and export macro.
// #include "vtkAbstractArray.h" // For arguments/returns.
#include "vtkStringToken.h" // For GetType().
#include "vtkType.h" // For AsArray() default argument.
#include "vtk_nlohmannjson.h"

#include <iostream>

VTK_ABI_NAMESPACE_BEGIN

class vtkAbstractArray;
class vtkDataArray;

class VTKCOMMONCORE_EXPORT vtkJSON
{
public:
  vtkJSON() = default;
  virtual ~vtkJSON() = default;
  vtkJSON(const vtkJSON&) = default;
  vtkJSON& operator = (const vtkJSON&) = default;
  vtkJSON(bool value) : Data(value) {}
  vtkJSON(const std::string& value) : Data(value) {}
  vtkJSON(std::int64_t value) : Data(value) {}
  vtkJSON(std::uint64_t value) : Data(value) {}
  vtkJSON(double value) : Data(value) {}
  vtkJSON(vtkAbstractArray* value);

  // Dump pretty-printed contents to \a os.
  void PrintSelf(ostream& os = std::cout);

  /// Convert internal JSON data into the given format.
  ///
  /// This method will throw a std::logic_error if no conversion is possible.
  template<typename T>
  T get()
  {
    try
    {
      return this->Data.get<T>();
    }
    catch (nlohmann::json::exception& e)
    {
      throw std::logic_error(e.what());
    }
  }

  vtkJSON contains(const std::string& key)
  {
    return this->Data.contains(key);
  }

  /// Return the value at a given \a key, throwing std::invalid_argument if
  /// no \a key exists.
  vtkJSON at(const std::string& key) const
  {
    try
    {
      return this->Data.at(key);
    }
    catch (nlohmann::json::exception& e)
    {
      throw std::invalid_argument(e.what());
    }
  }

  /// Return the value at a given array \a index.
  ///
  /// If this object does not hold an array, std::logic_error is thrown.
  vtkJSON operator[] (std::size_t& index)
  {
    try
    {
      return this->Data[index];
    }
    catch (nlohmann::json::exception& e)
    {
      throw std::logic_error(e.what());
    }
  }

  /// Return the value at a given dictionary \a key.
  ///
  /// This method will throw std::logic_error if the object is not
  /// a dictionary (i.e., it holds a number, string, or array).
  vtkJSON operator[] (const std::string& key)
  {
    try
    {
      return this->Data[key];
    }
    catch (nlohmann::json::exception& e)
    {
      throw std::logic_error(e.what());
    }
  }

  vtkStringToken type() const
  {
    using namespace vtk::literals;
    switch (this->Data.type())
    {
    case nlohmann::json::value_t::null: return "null"_token;
    case nlohmann::json::value_t::boolean: return "boolean"_token;
    case nlohmann::json::value_t::string: return "string"_token;
    case nlohmann::json::value_t::number_integer: return "signed integer"_token;
    case nlohmann::json::value_t::number_unsigned: return "unsigned integer"_token;
    case nlohmann::json::value_t::number_float: return "floating-point"_token;
    case nlohmann::json::value_t::object: return "dictionary"_token;
    case nlohmann::json::value_t::array: return "array"_token;
    case nlohmann::json::value_t::binary: return "binary blob"_token;
    case nlohmann::json::value_t::discarded: return "discarded"_token;
    }
  }

  /// A python-wrappable method to convert the data to a boolean value.
  bool AsBoolean() const
  {
    try
    {
      return this->Data.get<bool>();
    }
    catch (nlohmann::json::exception& e)
    {
      throw std::logic_error(e.what());
    }
  }

  /// A python-wrappable method to convert the data to a string value.
  std::string AsString() const
  {
    try
    {
      return this->Data.get<std::string>();
    }
    catch (nlohmann::json::exception& e)
    {
      throw std::logic_error(e.what());
    }
  }

  /// A python-wrappable method to convert the data to a signed integer value.
  std::int64_t AsSignedInteger() const
  {
    try
    {
      return this->Data.get<std::int64_t>();
    }
    catch (nlohmann::json::exception& e)
    {
      throw std::logic_error(e.what());
    }
  }

  /// A python-wrappable method to convert the data to an unsigned integer value.
  std::uint64_t AsUnsignedInteger() const
  {
    try
    {
      return this->Data.get<std::uint64_t>();
    }
    catch (nlohmann::json::exception& e)
    {
      throw std::logic_error(e.what());
    }
  }

  /// A python-wrappable method to convert the data to a floating-point value.
  double AsFloatingPoint() const
  {
    try
    {
      return this->Data.get<double>();
    }
    catch (nlohmann::json::exception& e)
    {
      throw std::logic_error(e.what());
    }
  }

  /// A python-wrappable method to convert the data to a VTK array.
  ///
  /// If this object cannot be interpreted as an array of the requested \a arrayType,
  /// a std::logic_error will be thrown.
  vtkSmartPointer<vtkAbstractArray> AsArray(int arrayType = VTK_VARIANT) const;

  /// A python-wrappable method to convert the data to a VTK array.
  ///
  /// If this object cannot be interpreted as an array of the requested \a arrayType,
  /// the method will return false (but the contents of \a array may be altered).
  /// This method will not throw exceptions.
  bool CopyInto(vtkAbstractArray* array) const;

  /// Construct a VTK array of the given \a ArrayType and populate it with this object's data.
  ///
  /// This method may throw a std::logic_error if the JSON data cannot be converted.
  template<typename ArrayType>
  vtkSmartPointer<ArrayType> AsArrayOfType()
  {
    auto result = vtkSmartPointer<ArrayType>::New();
    this->CopyInto(result);
    return result;
  }

  /// A python-wrappable method to convert the data to a VTK data-array.
  ///
  /// If this object cannot be interpreted as an array of the requested \a arrayType,
  /// a std::logic_error will be thrown.
  vtkSmartPointer<vtkDataArray> AsDataArray(int arrayType = VTK_DOUBLE) const;

  /// Return the size of this data (the number of keys if a dictionary, the number of values if
  /// an array, 0 for null, and 1 for plain-old-data types such as strings or numbers).
  std::size_t size() const
  {
    return this->Data.size();
  }

  /// Return true if this data is null or an empty dictionary or array.
  bool empty() const
  {
    return this->Data.empty();
  }

  /// Return a string token holding the type of JSON data.
  vtkStringToken GetType() const { return this->type(); }

  /// Return the size of this data (the number of keys if a dictionary, the number of values if
  /// an array, 0 for null, and 1 for plain-old-data types such as strings or numbers).
  std::size_t GetSize() const { return this->size(); }

  /// Return true if this data is null or an empty dictionary or array.
  bool IsEmpty() const { return this->empty(); }

  /// Set a dictionary entry.
  ///
  /// These implementations will change to handle exceptions.
  void SetValue(const std::string& key, bool value) { this->Data[key] = value; }
  void SetValue(const std::string& key, const std::string& value) { this->Data[key] = value; }
  void SetValue(const std::string& key, std::uint64_t value) { this->Data[key] = value; }
  void SetValue(const std::string& key, std::int64_t value) { this->Data[key] = value; }
  void SetValue(const std::string& key, double value) { this->Data[key] = value; }

  /// Set an array entry.
  ///
  /// These implementations will change to handle exceptions.
  void SetValue(std::size_t key, bool value) { this->Data[key] = value; }
  void SetValue(std::size_t key, const std::string& value) { this->Data[key] = value; }
  void SetValue(std::size_t key, std::uint64_t value) { this->Data[key] = value; }
  void SetValue(std::size_t key, std::int64_t value) { this->Data[key] = value; }
  void SetValue(std::size_t key, double value) { this->Data[key] = value; }

protected:
  /// Construction from nlohmann::json objects is not part of the public API.
  vtkJSON(const nlohmann::json& data)
    : Data(data)
  {
  }

  nlohmann::json Data;
};

class vtkJSONRaw : public vtkJSON
{
public:
  vtkJSONRaw(vtkJSON&& value);
  vtkJSONRaw(const vtkJSON& value) : Data(value.Data) {}
  vtkJSONRaw(const nlohmann::json& value) : Data(value) {}
  nlohmann::json& GetData() { return this->Data; }
  const nlohmann::json& GetData() const { return this->Data; }
};

VTK_ABI_NAMESPACE_END
#endif

```

Please feel free to comment. Comments on the overall approach (allowing exceptions but converting them to `std::exception`; sticking to the nlohmann::json API but also adding VTK-style accessors) are more valuable at this point that nitpicks on the suggested implementation details as there will be a merge request for that.

---

<div class="post-metadata">

### Author: ![jaswantp](https://discourse.vtk.org/user_avatar/discourse.vtk.org/jaswantp/32/10046_2.png) [@jaswantp](https://discourse.vtk.org/u/jaswantp)
#### Post date: [January 16, 2025, 6:06pm UTC](https://discourse.vtk.org/t/nlohmann-json-and-vtks-public-api/15131/13 "2025-01-16T18:06:13Z")

</div>

@dcthomp,  
We would like to avoid inclusion of third party headers in a VTK header that gets installed.

I see that it includes `vtk_nlohmannjson.h` in the header. It uses `nlohmann::json Data` under `protected` without actually including `#include VTK_NLOHMANN_JSON(json.hpp)`.

It is unclear how you have access to `nlohmann::json`. Am I missing something?

It should probably have a private `vtkInternals` instance, which, in the `vtkJSON.cxx` file is declared with a `nlohmann::json Data` member. That C++ file can do `#include VTK_NLOHMANN_JSON(json.hpp)`

In _vtkJSON.h_

```auto
#ifndef vtkJSON_h
#define vtkJSON_h

#include "vtkCommonCoreModule.h" // for export macro

VTK_ABI_NAMESPACE_BEGIN
class VTKCOMMONCORE_EXPORT vtkJSON
{
public:
/// All API without nlohmann::json
private:
  class vtkInternals;
  std::unique_ptr<vtkInternals> Internals;

class vtkJSONRaw may need rethinking because we cannot have nlohmann::json in this header.
};
VTK_ABI_NAMESPACE_END
#endif

```

In _vtkJSON.cxx_

```auto
#include "vtkJSON.h"

#include "vtk_nlohmannjson.h"
#include VTK_NLOHMANN_JSON(json.hpp)

VTK_ABI_NAMESPACE_BEGIN
class vtkJSON::vtkInternals
{
public:
  nlohmann::json Data;
}

// Implement vtkJSON functions..

VTK_ABI_NAMESPACE_END

```

---

<div class="post-metadata">

### Author: ![dcthomp](https://discourse.vtk.org/user_avatar/discourse.vtk.org/dcthomp/32/60_2.png) [@dcthomp](https://discourse.vtk.org/u/dcthomp)
#### Post date: [January 16, 2025, 6:49pm UTC](https://discourse.vtk.org/t/nlohmann-json-and-vtks-public-api/15131/14 "2025-01-16T18:49:08Z")

</div>

This would prevent or greatly complicate a templated `get<>()` method.

---

<div class="post-metadata">

### Author: ![dgobbi](https://discourse.vtk.org/user_avatar/discourse.vtk.org/dgobbi/32/18_2.png) [@dgobbi](https://discourse.vtk.org/u/dgobbi)
#### Post date: [January 16, 2025, 7:01pm UTC](https://discourse.vtk.org/t/nlohmann-json-and-vtks-public-api/15131/15 "2025-01-16T19:01:30Z")

</div>

Templated `get<>` methods are unwrappable. VTK doesn’t have a templated `get<>` method for vtkVariant, either. Maybe it’s something that could be considered for the more distant future, but not for the initial implementation.

---

<div class="post-metadata">

### Author: ![dcthomp](https://discourse.vtk.org/user_avatar/discourse.vtk.org/dcthomp/32/60_2.png) [@dcthomp](https://discourse.vtk.org/u/dcthomp)
#### Post date: [January 16, 2025, 7:50pm UTC](https://discourse.vtk.org/t/nlohmann-json-and-vtks-public-api/15131/16 "2025-01-16T19:50:52Z")

</div>

I had hoped to have templated `get<>()` for the C++ side and provided the `AsString()`, `AsFloatingPoint()`, … for the python wrapping.

But it sounds like `get<>()` is out altogether. ☹

---

<div class="post-metadata">

### Author: ![dgobbi](https://discourse.vtk.org/user_avatar/discourse.vtk.org/dgobbi/32/18_2.png) [@dgobbi](https://discourse.vtk.org/u/dgobbi)
#### Post date: [January 16, 2025, 9:43pm UTC](https://discourse.vtk.org/t/nlohmann-json-and-vtks-public-api/15131/17 "2025-01-16T21:43:55Z")

</div>

Ah, I didn’t scroll down far enough to see `AsString()` et al.

Mostly for the benefit of others reading this, the `get<>` declaration doesn’t need `json.hpp`, if its instantiations are declared `extern`. It’s a bit complicated but there’s precedent: a good current example in VTK is [vtkValueFromString.h](https://gitlab.kitware.com/vtk/vtk/-/blob/bd19fc22/Common/Core/vtkValueFromString.h#L59) and [vtkValueFromString.cxx](https://gitlab.kitware.com/vtk/vtk/-/blob/bd19fc22/Common/Core/vtkValueFromString.cxx#L362).

If wrapping of `get<>`, is eventually implemented, would ideally be able to guess the best-fit template type, so that `obj.get()` would simply return the json value as a native Python value (looking far into the future).

---

<div class="post-metadata">

### Author: ![ben.boeckel](https://discourse.vtk.org/letter_avatar_proxy/v4/letter/b/ea5d25/32.png) [@ben.boeckel](https://discourse.vtk.org/u/ben.boeckel)
#### Post date: [January 17, 2025, 2:33pm UTC](https://discourse.vtk.org/t/nlohmann-json-and-vtks-public-api/15131/18 "2025-01-17T14:33:14Z")

</div>

> [@dgobbi](#):
>
> If wrapping of `get<>`, is eventually implemented, would ideally be able to guess the best-fit template type, so that `obj.get()` would simply return the json value as a native Python value (looking far into the future).

Quoting my previous reply:

> [@ben.boeckel](#):
>
> Note that wrappers might be able to do marshalling to more language-ergonomic representations (e.g., taking/returning a Python dictionary).

---

<div class="post-metadata">

### Author: ![dcthomp](https://discourse.vtk.org/user_avatar/discourse.vtk.org/dcthomp/32/60_2.png) [@dcthomp](https://discourse.vtk.org/u/dcthomp)
#### Post date: [January 17, 2025, 3:43pm UTC](https://discourse.vtk.org/t/nlohmann-json-and-vtks-public-api/15131/19 "2025-01-17T15:43:08Z")

</div>

> [@dgobbi](#):
>
> … the `get<>` declaration doesn’t need `json.hpp`, if its instantiations are declared `extern`.

This might work for a free function but does it work for templated class methods?

---

<div class="post-metadata">

### Author: ![dgobbi](https://discourse.vtk.org/user_avatar/discourse.vtk.org/dgobbi/32/18_2.png) [@dgobbi](https://discourse.vtk.org/u/dgobbi)
#### Post date: [January 17, 2025, 4:03pm UTC](https://discourse.vtk.org/t/nlohmann-json-and-vtks-public-api/15131/20 "2025-01-17T16:03:47Z")

</div>

> [@dcthomp](#):
>
> This might work for a free function but does it work for templated class methods?

Hmm, maybe not. If the templated method needs to call an extern template friend free function then the resulting code is not pretty.

[Next page](https://discourse.vtk.org/t/nlohmann-json-and-vtks-public-api/15131.md?page=2)
