Sol2: Equality of usertypes, kind of an unexpected behaviour?

Created on 24 Aug 2016  路  12Comments  路  Source: ThePhD/sol2

Consider the following code:

#include <sol.hpp>

int main()
{
    sol::state lua;
    lua.open_libraries(sol::lib::base, sol::lib::io);

    class T {};
    lua.new_usertype<T>("T");

    T t;
    lua["t1"] = &t;
    lua["t2"] = &t;
    lua.script("print(t1 == t2)");

    return 0;
}

The code above outputs false, whereas I would expect it outputs true.
How can I correct this behaviour?

System:

ArchLinux
g++ 6.1.1 20160802
Lua 5.3.3
I have the latest version of single/sol.hpp.

Bike.Shed Feature.Shiny Maybe.Bug...?

Most helpful comment

All 12 comments

You can use sol::meta_function::equal_to to bind a method that calls operator==.

I disagree that this is unintuitive as your type has no ==, however, it'd be awesome if it could be automagically bound via the operator== method. Even if it was partial magic and we had to specify sol::bind_operators or something.

Sol has no idea that the two pointers you put into the system represent the same object. It creates a new userdata each time. I might consider adding what @Nava2 said, but even then that's a bit impractical.

The below code should do what you want, provided you get the (new) latest that I backported the change into: https://github.com/ThePhD/sol2/releases/tag/v2.12.0

#include <sol.hpp>

int main() {
    sol::state lua;
    lua.open_libraries(sol::lib::base, sol::lib::io);

    class T {};
    lua.new_usertype<T>("T");

    T t;
    lua["t1"] = &t;
    lua["t2"] = lua["t1"];
    lua.script("print(t1 == t2)");

    return 0;
}

That should print true. (Before it was printing false because it would see the proxy generated from lua[...] had a function, so it would serialize it as a function. Now it treats it properly, which is why you need to grab the _latest_ latest. Sorry about the re-release in so short a time!)

I agree that maybe it's not the most intuitive, but Lua compares primitives based on its own behavior. I could look into specifically auto-adding a __equal metamethod in the case of pointers and other objects that already have == defined, but that's going to take a lot of work and I'm tired and dreading school in a few weeks.

As a side note to my future self who will unlazy themself in probably 2 hours time:

__eq: equality
__lt: less than
__le: less than equal to

Visual Studio 2015 doesn't support decltype() SFINAE fully, so need to find a way to 'detect' if it has relational operators. If it has, add it in (if the above keys aren't already supplied and the user has custom logic). If it doesn't do not add them in and override.

Problem: users will expect userdata references set to each other to be equal. Will this conflict with Lua behavior? Does it break any previous userdata1 == userdata2 kinds of code that did not have a __eq/__lt/__le method defined?

Have to find out and try to write test cases around it.

Oh, and of note: using equal_to seems to fail with clang on both osx and linux. Not sure why, it passes with gcc and msvc, though. Part of my day today is trying to fix this.

sol::meta_function::equal_to? Any example code?

Can't test this, but I have something like:


struct Foo {
  bool operator==(const Foo&) const { return true; }
};

sol::usertype<Foo> ut(sol::meta_function::equal_to, [](const Foo& lhs, const Foo& rhs) { return lhs == rhs; });
lua.set_usertype(ut);

E: Using sol::overload, it looks like.

@Nava2 @jnbrq Coming soon:
Woo

It does lt, le, and eq, with the caveat that equal-to will always perform a pointer comparison at minimum, or do a full on comparison of the two objects if an op== is present.

I don't feel like I should intrinsically support math operators and such without the user explicitly asking for them, however, but others could feel differently?

This is awesome! What about overloaded operators that have different types? I think that'd be a reasonable caveat, but also something to consider

Fundamentally, that's impossible in Lua. Emphasis mine:

__eq - Check for equality. This method is invoked when "myTable1 == myTable2" is evaluated, but only if both tables have the exact same metamethod for __eq

It would be extremely hard to share a metatable to make them all point to the same function, so no-go on that idea (remind me later to add that to the docs or something).

http://sol2.readthedocs.io/en/latest/api/usertype.html#usertype-regular-function-options

This is now documented here and the code is in, tests should pass, you should be good to go...

Was this page helpful?
0 / 5 - 0 ratings

Related issues

patlecat picture patlecat  路  7Comments

Murloc992 picture Murloc992  路  7Comments

elfring picture elfring  路  10Comments

Koncord picture Koncord  路  4Comments

squeek502 picture squeek502  路  3Comments