I've started using the Foreign structure and it seems to be working well in tests. (It will probably be a week until I can test it with larger applications though.) My comments below are just for interest, nothing significant to report.

I have a minor comment about the type of the store function in conversions:
  Memory.voidStar * 'a -> unit -> unit
Every time I used a store function, I found that it would be more convenient to have
  'a -> Memory.voidStar -> unit -> unit
There were two reasons:
 1. To easily compose store functions, e.g.
      val cX : x conversion =
        makeConversion {
          load  = toX o load,
          store = store o fromX,  <--- not valid
          ctype = ctype
        }
2. To apply just the value being stored to get a type that contains no type variables, e.g.
      storeInt 3 : Memory.voidStar -> unit -> unit

I'm not actually using Foreign directly but via a module PolyMLFFI to provide a suitable interface. This gives a type-safe interface for creating calls, callback closures and struct conversions without using an infinite family of functions for each, e.g.
  open PolyMLFFI
  val aCall = call aSym (cInt &&> cInt --> cDouble)
The "price to pay" for this is that arguments or struct fields are joined using an infix pair constructor in ML, e.g.
  aCall (2 & 3)
(This would be nicer if SML allowed user-defined infix type constructors...)
This module also provides a low-level interface that is slightly higher-level than Foreign.LowLevel because it takes care of storing the arguments in memory. This can be used with the ctype, load and store components of a conversion, e.g.
  fun f m n =
    LowLevel.call fSym
      [cTypeInt,   cTypeInt]   cTypeInt
      [storeInt m, storeInt n] loadInt

I've attached this interface module, PolyMLFFI, in case it is useful to anyone. Also, I am interested in any comments, particularly regarding efficiency. (Currently it doesn't support cStar because updateC and updateML fields are not exposed by Foreign. It could be updated but I didn't need those.)

Phil


On 16/12/2015 12:35, David Matthews wrote:
There have been a few changes to the Foreign structure.  The callN
functions have been renamed as buildCallN and the way functions are
passed as arguments has been changed.

The reason for the changes is to make clear that the expensive
operations are creating the C functions and closures and that calling a
C function or passing a constructed closure are comparatively cheap.

It is important to call the buildXXX functions at the top-level e.g. in
a structure, so that the C function is created once.  The old callN
functions were curried and it wasn't apparent that the partial
application to the conversions was quite different to the application of
this to the arguments.  For that reason the buildXXX take a tuple.

David

_______________________________________________
polyml mailing list
polyml@inf.ed.ac.uk
http://lists.inf.ed.ac.uk/mailman/listinfo/polyml



Attachment: PolyMLFFI.tar.gz
Description: GNU Zip compressed data

_______________________________________________
polyml mailing list
polyml@inf.ed.ac.uk
http://lists.inf.ed.ac.uk/mailman/listinfo/polyml

Reply via email to