swig
swig copied to clipboard
Type conversion of "this" argument
MATLAB's multiple dispatch works differently from a member function in C++. If you wrap a class such as (i):
struct foo {
double v_;
foo (double v) : v_(v) { } // implicit type conversion!
foo operator+( const foo& b) const { return v_ + b.v_);}
};
It will generate something along the lines of (ii):
classdef foo
methods
function varargout = plus(self, varargin)
...
end
end
which really corresponds to something like (iii):
struct foo {
double v_;
foo (double v) : v_(v) { } // implicit type conversion!
friend foo operator+( const foo& a, const foo& b) const { return a.v_ + b.v_);}
};
The MATLAB class (ii) and the second C++ snippet (iii) will happily accept input such as 3 + foo(2)
and foo(2) + 3
, whereas (i) will accept foo(2) + 3
but not 3 + foo(2)
. I think that it makes sense to have (i) always behave like (iii) but for that to work an input typemap from self to type foo is needed.
Finally, if you would try to wrap (iii) using SWIG, it would create a global function plus.m, which is most definitely not what you want. That function will override basic behavior such as 3 + 2
, which you don't want. So it's important that the function plus remains in the class scope.
@wsfulton - do you know how to achieve this?
I figured that the best approach is to add a feature called "convertself" and then emit some additional typemap code whenever "qualifier" is "q(const).", i.e.
if (GetFlag(n, "feature:convertself") && checkAttribute(n, "qualifier", "q(const).")) {
... do something
}
Is this the correct approach? And how do I emit typemap code for self?
I committed an attempt that appears to work. I just added the type conversion on the MATLAB side. Not really a pretty solution, but I guess OK for now.
Can't you use instead use different typemaps for SWIGTYPE and SWIGTYPE const ? Using features for type handling doesn't seem right, that is what typemaps are for.
On 27 January 2015 at 13:40, Joel Andersson [email protected] wrote:
Closed #10 https://github.com/jaeandersson/swig/issues/10.
— Reply to this email directly or view it on GitHub https://github.com/jaeandersson/swig/issues/10#event-225355281.
Yeah, the correct way is definitely to use typemaps. Wasn't sure how to do it though. Now that it at least works I think I'd prefer to focus on other open issues.
I'm reopening this. The current design is not safe, cf. https://github.com/casadi/casadi/issues/1463. The correct solution to this would be to use typemaps as @wsfulton suggested above. That does not cover all the cases however, so to be able to handle a standard math operations such as "plus", "mtimes" -- operations that would typically be handled by friend functions in C++ -- one would need to find a way to:
- create a "global" function, but without any corresponding non-member function in MATLAB.
- call this global function from member functions in each class that defines such a friend function.
E.g. consider the following two classes in C++:
class A {
public:
// Implicit type conversion from double
A(double a);
// Calculate *this + b
A add(const A& b) const;
// Friend function, allows syntax such as "4 + A(4)"
inline friend A operator+(const A& x, const A& y) { return x.add(y);}
};
class B {
public:
// Implicit type conversion from double
B(double a);
// Implicit type conversion from A
B(const A& a);
// Calculate *this + b
B add(const B& b) const;
// Friend function, allows syntax such as "4 + B(4)" or "A(4) + B(4)"
inline friend B operator+(const B& x, const B& y) { return x.add(y);}
};
Given MATLAB is for maths, I think this is a pretty important case to be able to handle.
The way I think this should be handled is to first create a "global function" corresponding to the wrap the additions corresponding to the C++ global functions:
A operator+(const A& x, const A& y);
B operator+(const B& x, const B& y);
(thanks to the friend declarations, we can pretend that such overloads exists for the purpose of wrapping)
Here it would be tempting to create a global function for addition in MATLAB, e.g. a function called "plus", but this is almost certainly not what a user wants, since it would capture operations that do not involve "A" or "B", e.g. adding to constants "4 + 4", breaking almost any user code.
Instead, "plus" has to be placed as member functions of the classes "A" and "B", but still calling the "global" plus function:
% proxy of A
classdef A < swigRef
methods
function z = plus(x, y)
z = MySwigModule_wrap(1029, x, y); % some wrapper as below
end
end
end
% proxy of B
classdef B < swigRef
methods
function z = plus(x, y)
z = MySwigModule_wrap(1029, x, y); % some wrapper as above
end
end
end
I think the prettiest solution is adding a feature that, when wrapping a global function, places the proxy function not globally, but as member function in all of the classes corresponding to the arguments.