swig icon indicating copy to clipboard operation
swig copied to clipboard

Type conversion of "this" argument

Open jaeandersson opened this issue 10 years ago • 6 comments

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.

jaeandersson avatar Dec 15 '14 23:12 jaeandersson

@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?

jaeandersson avatar Jan 27 '15 13:01 jaeandersson

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.

jaeandersson avatar Jan 27 '15 13:01 jaeandersson

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.

wsfulton avatar Jan 29 '15 22:01 wsfulton

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.

jaeandersson avatar Jan 29 '15 23:01 jaeandersson

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:

  1. create a "global" function, but without any corresponding non-member function in MATLAB.
  2. 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

jaeandersson avatar Jul 01 '15 14:07 jaeandersson

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.

jaeandersson avatar Jul 16 '15 17:07 jaeandersson