Assume the following situation: I have a WolframLibrary function which gets as parameter an integer tensor (which is for simplicity of rank 1) and the function should return an integer list through MathLink.

My question is about the used types in this function only. The start of such a function could look like the following, where I use WolframLibrary functions declared in WolframLibrary.h

EXTERN_C DLLEXPORT mint func( WolframLibraryData lib, mint argc,
MArgument *args, MArgument return_value)
{
MTensor tensor_u0 = MArgument_getMTensor(args[0]);
mint *u0 = lib->MTensor_getIntegerData(tensor_u0);
// ...
}


The full declaration of the last function is

mint* (*MTensor_getIntegerData)( MTensor);


The array u0 contains the linear data of our tensor. Let's say I worked with this array, I used consistently mint in all procedures and I want to send now the mint *result array back through MathLink.

In the MathLink API we have several functions for sending integer lists

int MLPutInteger16List(MLINK link, short *a,int n)


Usually you just use MLPutIntegerList which uses the integer type of the machine. Unfortunately, since version 9 the MathLink integer type and the WolframLibrary integer type differ on my machine.

Additionally, the types used in MathLink seem to be completely unrelated to the WolframLibrary types. While I can use the types in a pure WolframLibrary function consistently and hopefully portable, mixing those two technologies seems not possible easily.

What I would have to do is to look up the underlying type of mint, which is long on my machine here, but int on the Windows machine of my colleague and probably long long on our Windows 7 64bit box. After that I can select the appropriate MLPut... function for my special system. This is not portable and I basically have to repeat all system-dependent #ifdefs which are already there in mathlink.h and friends.

Question: What am I missing here? There must be a portable and consistent way to cast both types.

-
@ToddGayley In case you missed this question. Some insight or corrections would be highly appreciated. –  halirutan Feb 10 '13 at 2:16
Just an idea without much thought put into it (sorry if I overlooked something): if you're using C++, create a single overloaded function that calls MLPutInteger16List, MLPutInteger32List or MLPutInteger64List depending on the type of arguments, then use this function. The compiler will figure out which version of the overloaded function to call when you pass it a mint *, and you won't need to think about it as a user or disambiguate with lots of #defines and #ifdefs and anticipating various types ... –  Szabolcs Feb 13 '13 at 21:45

What you observed is a bit unfortunate because these libraries should be easy to use together (because they're meant to be used together).

Here's a "workaround" that could make your life easier in certain cases. You can use C++ instead of C and take advantage of overloaded functions. I have a header called mlp.h with the following:

#include <mathlink.h>

}

}

}

// ... similar overloaded versions for other MLPut* functions.
// might need some for long long or compiler specific types too


Then instead of calling one of the MLPutIntegerList functions explicitly, call mlpPutIntegerList:

mint *u0 = ...


For as long as you can be sure that mint is one of short, int, or long, the compiler will figure out the correct overload to call, and you can use the same source code on all platforms.

One situation where this may potentially go wrong is if mint is not a standard integer type but something else (e.g. a struct). I don't believe that this can be the case, but theoretically it's possible. For example, mlint64 is a struct on 32-bit platforms.

I have used this approach to connect MathLink with another library where the other library has a custom integer type that had different sizes (and different underlying types) on various platforms.

Also, this takes some work, but it's cleaner than using many #ifdefs and it's also more easily re-usable across projects.

-
Of course +1 for this nice answer. I probably prefer a C++ template solution because all code is generated at compile time and has no overhead when using it, but your overloading version is maybe easier to understand. Honestly I was hoping for an answer of someone from WRI to understand how it meant to be used ;-) –  halirutan Feb 17 '13 at 12:43

This is a runtime solution. I would prefer a compile time solution, but I guess that is difficult. An advantage is that this does not use C++, just C.

switch(sizeof(mint))
{
case 2:
break;
case 4:
break;
case 8:
break;
}


We do not have to worry that the mlint that MLPutInteger expects can be a struct or something strange like that, as from the docs of mlint64 we have:

On 64-bit machines, mlint64 is a native 64-bit C type

By the way, if you have linked with LibraryLink and consistently worked with mints, why not "send"(/share) the data using LibraryLink? To me that is the main advantage of using LibraryLink :).

-
Let me know if I missed the point :P. Maybe you just thought this solution was worse than "repeating the system-dependent #ifdefs which are already there in mathlink.h and friends", which doesn't sound terrible to me :) –  Jacob Akkerboom Dec 5 '13 at 19:04
One should be careful--this may not actually be a runtime solution since sizeof(mint) is fixed at compile time and the switch may therefore be optimized away altogether, rendering the resulting library just as nonportable as with the #ifdef approach. –  Oleksandr R. Dec 5 '13 at 20:37