# Predicates for over-loaded C++ functions

**URL:** <https://swi-prolog.discourse.group/t/predicates-for-over-loaded-c-functions/7474>\
**Category:** General\
**Created:** [May 26, 2024, 8:57pm UTC](https://swi-prolog.discourse.group/t/predicates-for-over-loaded-c-functions/7474 "2024-05-26T20:57:43Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![pizzapal](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/pizzapal/32/5776_2.png) [@pizzapal](https://swi-prolog.discourse.group/u/pizzapal)\
**Post date:** [May 26, 2024, 8:57pm UTC](https://swi-prolog.discourse.group/t/predicates-for-over-loaded-c-functions/7474/1 "2024-05-26T20:57:43Z")

</div>

One of the things I like about C++ is overloading function parameters because it can allow for programs that are organized in more of a pattern-matching style. I’m trying to find a safe and efficient way to expose overloaded C++ functions as Prolog predicates with multiple clauses using the SWI-Prolog C++ FFI.

Here is an example of my `PlBlob` subclasses and a overloaded function/multi-clause predicate mapping (followed by specific questions):

```cpp
struct blob_sfVertex;
static PL_blob_t blob_sf_vertex = PL_BLOB_DEFINITION (blob_sfVertex, "blob_sf_vertex");
struct blob_sfVertex : public PlBlob
{
  std::unique_ptr<sf::Vertex> foreign_object;
  PL_BLOB_SIZE
	
  //Default constructor
  explicit blob_sfVertex () 
    : PlBlob (&blob_sf_vertex), 
      foreign_object (std::make_unique<sf::Vertex> ())
  {}
  // Copy constructor
  explicit blob_sfVertex (sf::Vertex& x)
    : PlBlob (&blob_sf_vertex),
      foreign_object (std::make_unique<sf::Vertex> (x))
  {}
  explicit blob_sfVertex (const sf::Vector2f& thePosition,const sf::Vector2f& theTexCoords) 
    : PlBlob (&blob_sf_vertex), 
      foreign_object (std::make_unique<sf::Vertex> (thePosition,theTexCoords))
  {}
// More constructors...
};

```

I have my predicates defined like this

```cpp

/*
  %! sf_vertex_vertex(+Position:blob_sfVector2f, +TextureCoordinates:blob_sfVector2f, -Vertex:blob_sfVertex).
  %
  % Construct the vertex from its position and texture coordinates.
*/
PREDICATE (sf_vertex_vertex, 3)
{
  auto thePosition = PlBlobV<blob_sfVector2f>::cast_ex (A1, blob_sf_vector2f);
  auto theTexCoords = PlBlobV<blob_sfVector2f>::cast_ex (A2, blob_sf_vector2f);
	
  auto foreign_object = std::unique_ptr<PlBlob>
    (new blob_sfVertex (*thePosition->foreign_object,*theTexCoords->foreign_object));
  return A3.unify_blob (&foreign_object);
}

/*
  %! sf_vertex_vertex(+Position:blob_sfVector2f, +Color:blob_sfVector2f, -Vertex:blob_sfVertex).
  %
  % Construct the vertex from its position and color.
*/
PREDICATE (sf_vertex_vertex, 3)
{
  auto thePosition = PlBlobV<blob_sfVector2f>::cast_ex (A1, blob_sf_vector2f);
  auto theColor = PlBlobV<blob_sfColor>::cast_ex (A2, blob_sf_color);
	
  auto foreign_object = std::unique_ptr<PlBlob>
    (new blob_sfVertex (*thePosition->foreign_object,*theColor->foreign_object));
  return A3.unify_blob (&foreign_object);
}

```

As written, this code will not compile because the `PREDICATE` macro will evaluate to a redefinition of `sf_vertex_vertex`.

I can think of 3 ways of making this work:

1. Renaming the predicates so they are different names for each specialization. This is what I’ve done, temporarily, so I can compile the code and test the predicates. It might not be the worst thing in the world, but I don’t want keep it this way because I want the predicates to match the source interface ([sf::Vertex Class Reference (SFML / Learn / 2.6.1 Documentation)](https://www.sfml-dev.org/documentation/2.6.1/classsf_1_1Vertex.php)).

2. I thought I could use `PL_is_blob` and maybe some kind of RTTI to find out the type of a `PlTerm` argument, and then use some kind of switch statement to handle the right type.

3. Use `PREDICATE_NONDET` and handle the blob type casting exceptions to enter redo. I’d probably just keep the specially definitions described in 1. and iterate over them. I could also do this in Prolog and it would probably be equivalent?

Option 3. seems like the most natural because that’s what I’ve done when I’ve written predicates with differently typed parameters. Does that seem right?

---

<div class="post-metadata">

**Author:** ![peter.ludemann](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/peter.ludemann/32/48_2.png) [@peter.ludemann](https://swi-prolog.discourse.group/u/peter.ludemann)\
**Post date:** [May 26, 2024, 11:54pm UTC](https://swi-prolog.discourse.group/t/predicates-for-over-loaded-c-functions/7474/2 "2024-05-26T23:54:16Z")

</div>

> [@pizzapal](#):
>
> Use `PREDICATE_NONDET` and handle the blob type casting exceptions to enter redo. I’d probably just keep the specially definitions described in 1. and iterate over them. I could also do this in Prolog and it would probably be equivalent?

I don’t understand this (option 3).

I notice that your code uses `cast_ex()`. You could instead use `cast()` and check for `nullptr`. So, I _think_ that the following will do what you want (untested, and mainly done by copy&paste of your code). Note where I’ve changed your `cast_ex()` to `cast()`.

```cpp
PREDICATE(sf_vertex_vertex, 3) {
  auto thePosition = PlBlobV<blob_sfVector2f>::cast_ex(A1, blob_sf_vector2f);
  { auto theTexCoords = PlBlobV<blob_sfVector2f>::cast(A2);
    if (theTexCoords) {
      auto foreign_object = std::unique_ptr<PlBlob>(
          new blob_sfVertex(*thePosition->foreign_object, *theTexCoords->foreign_object));
      return A3.unify_blob(&foreign_object);
    }
  }

  { auto theColor = PlBlobV<blob_sfColor>::cast_ex(A2, blob_sf_color);
    auto foreign_object = std::unique_ptr<PlBlob>(
        new blob_sfVertex(*thePosition->foreign_object, *theColor->foreign_object));
    return A3.unify_blob(&foreign_object);
  }
}

```

---

<div class="post-metadata">

**Author:** ![pizzapal](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/pizzapal/32/5776_2.png) [@pizzapal](https://swi-prolog.discourse.group/u/pizzapal)\
**Post date:** [May 27, 2024, 7:26pm UTC](https://swi-prolog.discourse.group/t/predicates-for-over-loaded-c-functions/7474/3 "2024-05-27T19:26:47Z")

</div>

Thanks, your example code compiled and worked as expected when using the foreign libraries from Prolog (the only thing that I changed was to use `A2.as_atom()` because `cast` expects `PlAtom` instead of `PlTerm`).

I’m glad I asked because while I think I would have eventually figured out the `cast` vs. `cast_ex` distinction, I clearly had some fundamental misunderstandings about how the `PREDICATE` macro works. I had not realized that the macro lets you represent multiple clauses like that; I thought you had to use `PREDICATE_NONDET` if you wanted to keep searching for solutions after an initial failure.

Is my understanding of this correct? When using `PREDICATE`, if “bodies” { 1… }, { 2…}, and so on, are placed inside the outermost brackets as shown above, it’s as if each one is a clause that we can attempt to match?

---

<div class="post-metadata">

**Author:** ![peter.ludemann](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/peter.ludemann/32/48_2.png) [@peter.ludemann](https://swi-prolog.discourse.group/u/peter.ludemann)\
**Post date:** [May 28, 2024, 12:44am UTC](https://swi-prolog.discourse.group/t/predicates-for-over-loaded-c-functions/7474/4 "2024-05-28T00:44:18Z")

</div>

First off, the documentation for `PlBlobV<...>::cast()` and `cast_ex()` could be improved. PRs are welcome. 🙂

The general philosophy of the C++ interface is that wherever possible a function or method should throw an error (or, sometimes, `PlFail`) so that the code doesn’t have to check the result after every call – if you like the check-every-result style, you should probably use the C interface instead. So, for example, `A1.as_atom()` will throw an exception if `A1` isn’t an atom; if you want to test for a term being an atom, use `A1.is_atom()` (or catch the exception from `as_atom()`, which I don’t recommend).

In a few cases, it’s useful to have a version of the API that returns an error indication rather than throwing an error: `cast()` is an example of this (as opposed to `cast_ex()`).

I suppose, in retrospect, methods such as `as_atom()` should have been named `as_atom_ex()`, for consistency. However, the original C++ interface threw an error (it was a cast operator) and I continued with that, for better or worse.

As to overloading C++ functions for Prolog predicates …

`PREDICATE_NONDET` has three possible return values:

- `true` – success, and no more solutions
- `PL_retry_address(ctxt)` – success, and possibly more solutions
- `false` – failure, and no more solutions

I think what you’re asking for is a fourth value: failure, and possibly more solutions. This doesn’t exist.

A C++ predicate acts like a single-clause predicate in Prolog; there’s no failure to a second clause because there is no second clause. If you want to do multiple clauses, then you need to do something like this – but it can leave an unwanted choice point, so I recommend the single C++ function instead:

```prolog
sf_vertex_vertex(A1,A2,A3) :- sf_vertex_vertex_1(A1,A2,A3).
sf_vertex_vertex(A1,A2,A3) :- sf_vertex_vertex_2(A1,A2,A3).

```

```cpp
PREDICATE(sf_vertex_vertex_1, 3) {
  auto thePosition = PlBlobV<blob_sfVector2f>::cast_ex(A1, blob_sf_vector2f);
  auto theTexCoords = PlBlobV<blob_sfVector2f>::cast(A2.as_atom());
  if ( !theTexCoords )
    return false;
  auto foreign_object = std::unique_ptr<PlBlob>(
      new blob_sfVertex(*thePosition->foreign_object, *theTexCoords->foreign_object));
  return A3.unify_blob(&foreign_object);
}

PREDICATE(sf_vertex_vertex_2, 3) {
  auto thePosition = PlBlobV<blob_sfVector2f>::cast_ex(A1, blob_sf_vector2f);
  auto theColor = PlBlobV<blob_sfColor>::cast_ex(A2, blob_sf_color);
  auto foreign_object = std::unique_ptr<PlBlob>(
      new blob_sfVertex(*thePosition->foreign_object, *theColor->foreign_object));
  return A3.unify_blob(&foreign_object);
}

```
