purescript-native icon indicating copy to clipboard operation
purescript-native copied to clipboard

Returning a constant from the ffi

Open mikesol opened this issue 5 years ago • 7 comments

This isn't a bug but more of a question/potential point for documentation. I've been able to successfully implement functions in the FFI, but constants are proving a bit elusive for me. If I try to implement Global.infinity this way:

exports["infinity"] = []() -> boxed {
  return 1000.0;
};

And then I print it out later like this:

std::cout << "infinity " << unbox<double>(Global::infinity()) << std::endl;

I see the following output on the console:

infinity 6.90463e-310

I'm probably doing something wrong in the export, but I'm not quite sure how to get it to print the right number (in this case 1000.0, eventually I'll use the C++ infinity, but this is just a sanity check). Thanks in advance for your advice!

mikesol avatar Sep 08 '20 04:09 mikesol

The thunk for foreign values is implicit – the compiler creates the nullary accessor function for you – so your exports should just be the values you want to set. This is why foreign functions don't need to be wrapped in a nullary function either. So for your case, infinity should just be set to 1000.0 directly. See these examples from prelude.

andyarvanitis avatar Sep 08 '20 05:09 andyarvanitis

Great, thanks!

mikesol avatar Sep 08 '20 06:09 mikesol

I also hit this trying to bind to some enum values, following an example here https://github.com/lettier/purescript-native-ffi/blob/lambda-lantern/panda3d/panda3d.cpp#L910,

exports["textAlignCenter"] = []() -> boxed {
  return box<TextProperties::Alignment>(TextNode::A_center);
};

which is bound like so

foreign import data TextAlignment :: Type

foreign import textAlignCenter :: TextAlignment

I was getting garbage values as well and eventually guessed it was a pointer and removed the function and the box I had wrapped it in. But it makes me wonder if that example worked at some point. Did this behavior change?

joprice avatar Oct 01 '20 01:10 joprice

The FFI definitely changed when going from the older (pure11) implementation to the current one, so there might be some things left over from when people ported their code.

andyarvanitis avatar Oct 01 '20 01:10 andyarvanitis

Could this be a compiler warning? I realized recently that the purescript compiler actually parses the js in some way to detect unimplemented foreign values. I'd find this a very convenient alternative to the current runtime errors. I found this on stackage https://hackage.haskell.org/package/language-go.

joprice avatar Oct 06 '20 23:10 joprice

Yeah, it could be done, especially with a library like that available. However, I haven't planned on doing it. Earlier backends I created required the full FFI implemented (for every module dependency) during build time, but the issue there is that it's a big commitment (for one person, at least) to write them all. The dynamic method allows for just implementing whatever one needs for their program. Warnings (as you suggest) wouldn't be a bad compromise, but you'd get a lot of them and thus maybe lose some of that benefit (of seeing what's missing). However, I've been doing a bit of performance testing on the panic-on-type-assertion question (in the other issue comments) and I can't see any performance loss with the latest version of golang, so I'm inclined to move to the friendlier panic error messages (single return from type assertion) by default (or altogether), asap.

andyarvanitis avatar Oct 07 '20 01:10 andyarvanitis

There's also the idea of checking implemented ffi values to make sure they are correct (which maybe you were also getting at earlier). I haven't made plans for that either at this point.

andyarvanitis avatar Oct 07 '20 01:10 andyarvanitis