excel-d v0.0.1 - D API to write functions callable from Excel
Atila Neves via Digitalmars-d-announce
digitalmars-d-announce at puremagic.com
Mon Apr 24 14:59:34 PDT 2017
On Monday, 20 March 2017 at 20:09:58 UTC, Atila Neves wrote:
> http://code.dlang.org/packages/excel-d
>
> This dub package allows D code to be called from Excel. It uses
> compile-time reflection to register the user's code in an XLL
> (a DLL loaded by Excel) so no boilerplate is necessary. Not
> even `DllMain`! It works like this:
>
> main.d:
>
> import xlld;
> mixin(wrapAll!(__MODULE__, "funcs"));
>
> funcs.d:
>
> import xlld;
>
> @Register(ArgumentText("Array to add"),
> HelpTopic("Adds all cells in an array"),
> FunctionHelp("Adds all cells in an array"),
> ArgumentHelp(["The array to add"]))
> double FuncAddEverything(double[][] args) nothrow @nogc {
> import std.algorithm: fold;
> import std.math: isNaN;
>
> double ret = 0;
> foreach(row; args)
> ret += row.fold!((a, b) => b.isNaN ? 0.0 : a + b)(0.0);
> return ret;
> }
>
> This code, once compiled to an XLL (see the example in the
> repository) and loaded in Excel, will permit a user to write
> `=FuncAddEverything(B1:D6)` and have the cell populated with
> the sum of all arguments in that range.
>
> There's a lot going on behind the scenes, and that's the point.
> For instance, the function above takes a 2d array of doubles
> and returns a double, but those aren't Excel types. The wrapper
> code writes out an Excel-compatible type signature at
> compile-time, does all the conversions, calls the user's code
> then converts back to types Excel can understand.
>
> The user functions have to be `nothrow`. This is guaranteed at
> compile-time and the user gets a warning message about the
> function not being considered. `@nogc` is optional but won't
> work if returning a string due to allocations. The code is
> compatible with std.experimental.allocator internally but
> there's no way to specify an allocator currently for the
> registration.
>
> I can make the registration mixin easier to use but haven't
> gotten around to it yet. I thought it was better to put the
> code out there as is than wait.
>
> This is another one of those "only in D" packages due to the
> metaprogramming, which is always nice.
>
> Atila
Now with more `@nogc`. Before, this worked fine:
double func(double d) @nogc nothrow { return d * 2; }
The function is `@nogc`, the wrapper function (i.e. the function
that Excel actually calls) is also `@nogc` via the magic of
compile-time reflection. So far, so good. But what if you want to
return a string or an array back to Excel. Oh, oh...
Enter the `@Dispose` UDA:
// @Dispose is used to tell the framework how to free memory that
is dynamically
// allocated by the D function. After returning, the value is
converted to an
// Excel type sand the D value is freed using the lambda defined
here.
@Dispose!((ret) {
import std.experimental.allocator.mallocator: Mallocator;
import std.experimental.allocator: dispose;
Mallocator.instance.dispose(ret);
})
double[] FuncReturnArrayNoGc(double[] numbers) @nogc @safe
nothrow {
import std.experimental.allocator.mallocator: Mallocator;
import std.experimental.allocator: makeArray;
import std.algorithm: map;
try {
// Allocate memory here in order to return an array of
doubles.
// The memory will be freed after the call by calling the
// function in `@Dispose` above
return Mallocator.instance.makeArray(numbers.map!(a => a
* 2));
} catch(Exception _) {
return [];
}
}
And Bob's your uncle.
Atila
More information about the Digitalmars-d-announce
mailing list