Foreign Types Tutorial

Go to the tutorial main page.

With a good understanding of the foreign types system, Lisp users can interface to foreign libraries without having to write/compile any foreign code. It is very easy to manage foreign data directly from Lisp.

A good starting point for building foreign types is the syntax tree found in A syntax for foreign types in ftype.htm.

There are also basic examples throughout the ftype.htm document. Here is the example showing how we can define, allocate, set and access values in a foreign structure:

;; define the structure
user(3): (ff:def-foreign-type my-point (:struct (x :int) (y :int)))
#<foreign-functions::foreign-structure my-point>

;; allocate an object, using the default 
;; allocation type of :foreign
user(4): (setq obj (ff:allocate-fobject 'my-point))
#<foreign object of class my-point>

;; set a slot in the object
user(5): (setf (ff:fslot-value obj 'x) 3)
3

;; verify that the slot is set with the correct value
user(6): (ff:fslot-value obj 'x)
3

The new examples in this tutorial will focus on slightly more interesting cases.

Frequently used Foreign Type routines

The most important routines are:

An example defining a matrix foreign type

An often asked question is how to create 2d matrices of some type for passing to a foreign-function. Users typically want to implement on the Lisp side using arrays, but run into difficulties when trying to figure out how to correctly convert this for access by foreign code. It is easier to simply create the foreign matrix directly, as this code does.

;; define foreign type for matrix
(ff:def-foreign-type my-matrix (:array (* :double)))

;;  A function to create a foreign matrix
;;  Note the :c as the second (allocation) argument to 
;;  ff:allocate-fobject. That says allocate the object in
;;  foreign space and return a pointer to the location.
;;  The object will not be moved by Lisp garbage collections.
(defun make-foreign-matrix (rows cols)
  (let ((new-matrix (ff:allocate-fobject
                        '(* :double) :c
                        (* rows (ff:sizeof-fobject '(* :double)))))
        )
    (dotimes (i rows)
      (setf (ff:fslot-value-typed 'my-matrix :c new-matrix i)
            (ff:allocate-fobject :double :c
                (* cols (ff:sizeof-fobject :double)))))
    new-matrix)
  )

;; accessing cells in the matrix
(defmacro lookup-matrix (x row col)
  `(ff:fslot-value-typed 'my-matrix :c ,x ,row ,col))

;;  This macro is setfable. We use it to define another macro
;;  which sets values in the matrix:

(defmacro set-matrix-value (x row col newval)
  `(setf (lookup-matrix ,x ,row ,col) ,newval))

Assume we have defined in Lisp the my-matrix foreign type, the make-foreign-matrix function and the lookup-matrix macro. Here is a transcript showing these in use:

;;  We create a matrix. Note that its value is an integer corresponding 
;;  to an address, because the allocation type is :c (see the definition
;;  of MAKE-FOREIGN-MATRIX above). This address will remain valid even
;;  if Lisp does a garbage collection.
cl-user(71): (setq x (make-foreign-matrix 2 3))
1409564688

;;  We set the value of one of the elements:
cl-user(72): (set-matrix-value x 0 0 1.0d0)
1.0d0

;;  And that is the value we see:
cl-user(73): (lookup-matrix x 0 0)
1.0d0

;;  Looking at a not yet set (by us) value shows 0.0d0.
;;  The unset values cannot be depended on, however, as
;;  they may not be initialized as expected (and you may
;;  see a different value).
cl-user(74): (lookup-matrix x 0 1)
0.0d0

;;  We set the value to 4.0d0 and verify that is the new value:
cl-user(75): (set-matrix-value x 0 1 4.0d0)
4.0d0
cl-user(76): (lookup-matrix x 0 1)
4.0d0
cl-user(77): 

This is the end of the tutorial. The documentation for foreign types is in doc/ftype.htm.

Go to the tutorial main page.