Designing wrapper around C++ API with shared_ptrs


#1

Hi, I am trying to design wrapper around https://github.com/Microsoft/CNTK/blob/release/2.2/Source/CNTKv2LibraryDll/API/CNTKLibrary.h.

I have first version up and running, but I am quite unhappy with the ergonimics (and maybe that the wrapper seems like C++ forced into Rust).

I have functions with signature:

fn plus(x: &Variable, y: &Variable) -> Variable
fn times(x: &Variable, y: &Variable) -> Variable

In C++ the Variable class contains couple of shared_ptrs. Thus Variable type needs to implement Drop, thus cannot implement Copy, but still can be Cloned.

My problem is around ergonomics where composing functions. Current state is like this:

let w = Variable::new(...);
let b = Variable::new(...);
let x = Variable::new(...);
let res = plus(&times(&w, &x), &b);

The number of & feels quite high to me.

The question is: can this be fixed? Is any of following signatures better in communicating underlying intent:

fn plus(x: Variable, y: Variable) -> Variable

This would require couple of clones during calls (which I can live with and maybe better communicates the intent), but no & in function composition, which is nice.

fn plus<T: Borrow<Variable>, U: Borrow<Variable>>(x: T, y: U) -> Variable

This can be called either with reference or by value, but I feel, that it hides a lot of stuff and there are hidden implicit traps.

Second question: Since the most API variables are sort equivalents to Rc<T> or Rc<RefCell<T>> is the idiomatic way of passing Rc<T> to function by value or by reference?


#2

Usually the way I have wrapped C++ APIs in the past is to implement a C wrapper first. This adds some extra works but the wrapping code become much easier as you can hide all the C++:ish on the C/C++ behind the the wrapper code.