-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathchapter11.html
36 lines (35 loc) · 39.2 KB
/
chapter11.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<!DOCTYPE html>
<html>
<head>
<title>L.B.Stanza</title>
<link type="text/css" rel="stylesheet" href="resources/mainstyle.css">
<link type="text/css" rel="stylesheet" href="resources/documentation.css">
</head>
<body>
<table class="wrap">
<tr><td colspan="3" class="banner">
<a href="index.html">Home</a><a href="stanzabyexample.html">Table of Contents</a><a href="chapter10.html">Previous Chapter</a><a href="appendix.html">Next Chapter</a>
</td></tr>
<tr>
<td class="nav">
<h1>NAVIGATION</h1>
<h2><a href="#anchor386">Calling Foreign Functions</a></h2><h3><a href="#anchor105">Writing a C Function</a></h3><h3><a href="#anchor106">Calling our C Function</a></h3><h4><a href="#anchor387">Declaring an External Function</a></h4><h4><a href="#anchor388">Declaring a LoStanza Function</a></h4><h4><a href="#anchor389">C Functions that Return void</a></h4><h3><a href="#anchor107">Calling LoStanza from Stanza</a></h3><h4><a href="#anchor390">Convert Stanza Objects to LoStanza Values</a></h4><h4><a href="#anchor391">Convert LoStanza Values to Stanza Objects</a></h4><h3><a href="#anchor108">LoStanza Types</a></h3><h4><a href="#anchor392">Primitive Types</a></h4><h4><a href="#anchor393">Pointer Types</a></h4><h4><a href="#anchor394">Declaring a LoStanza Type</a></h4><h4><a href="#anchor395">Reference Types</a></h4><h4><a href="#anchor396">Literal Strings</a></h4><h4><a href="#anchor397">External Unknown Arity Functions</a></h4><h3><a href="#anchor109">External Global Variables</a></h3><h3><a href="#anchor110">Function Pointers</a></h3><h3><a href="#anchor111">The Address Operator</a></h3><h4><a href="#anchor398">Stable and Unstable Locations</a></h4><h3><a href="#anchor112">Calling LoStanza from C</a></h3><h3><a href="#anchor113">Passing Callbacks to C</a></h3>
</td>
<td class="main">
<h1 id="anchor386">Calling Foreign Functions</h1><p>One of the most important features that a practical programming language must support is the ability to call functions written in other languages. There are too many useful libraries written in the established languages to consider rewriting them in another programming language. Stanza provides support for calling any function using the calling convention for the C programming language. This means that you can use any library written in C, or that provides a C interface, in Stanza. Since the dominant consumer operating systems today use a C calling convention, this means that the vast majority of libraries can be called from Stanza. This chapter will show you how.</p><h2 id="anchor105">Writing a C Function</h2><p>Here is a fibonacci function written in C. Create a <code>fibonacci.c</code> file with the following contents.</p><pre><code>#include<stdio.h><br>#include<stdlib.h><br><br>int generate_fib (int n) {<br> int a = 0;<br> int b = 1;<br> while(n > 0){<br> printf("%d\n", b);<br> int c = a + b;<br> a = b;<br> b = c;<br> n = n - 1;<br> }<br> return 0;<br>}<br><br>int main (int nargs, char** argvs) {<br> generate_fib(10);<br> return 0;<br>}</code></pre> <p>Compile and run the above program by typing</p><pre><code>cc fibonacci.c -o fibonacci<br>./fibonacci</code></pre><p>in the terminal. It should print out</p><pre><code>1<br>1<br>2<br>3<br>5<br>8<br>13<br>21<br>34<br>55</code></pre><p>In the next step, we will call the <code>generate_fib</code> function from Stanza.</p><h2 id="anchor106">Calling our C Function</h2><p>The first step is just to remove the <code>main</code> function in <code>fibonacci.c</code> since the program is now being initialized and driven by Stanza.</p><p>Next create a file named <code>fib.stanza</code> with the following contents.</p><pre><code>defpackage fib :<br> import core<br> import collections<br><br>extern generate_fib: int -> int<br><br>lostanza defn call-fib () -> ref<False> :<br> call-c generate_fib(10)<br> return false<br><br>println("Calling fibonacci")<br>call-fib()<br>println("Done calling fibonacci")</code></pre><p>To compile both the <code>fib.stanza</code> and <code>fibonacci.c</code> files together, and run the program, type the following into the terminal.</p><pre><code>stanza fib.stanza -ccfiles fibonacci.c -o fib<br>./fib</code></pre><p>It should print out</p><pre><code>Calling fibonacci<br>1<br>1<br>2<br>3<br>5<br>8<br>13<br>21<br>34<br>55<br>Done calling fibonacci</code></pre><p>Thus our Stanza program successfully calls and returns from the <code>generate_fib</code> function written in C. Let's go through the program step by step.</p><h3 id="anchor387">Declaring an External Function</h3><p>The line </p><pre><code>extern generate_fib: int -> int</code></pre><p>declares that there is a function defined externally called <code>generate_fib</code> that takes a single integer argument and returns a single integer argument.</p><p>Notice that <code>int</code> is not capitalized. This is important. <code>int</code> refers to the <span style="font-style:italic;">LoStanza</span> integer type, and is different from the <span style="font-style:italic;">Stanza</span> type <code>Int</code>. We'll go over what this means later. </p><p>Let us suppose that <code>generate_fib</code> took two arguments instead of one. Make the following change to the <code>generate_fib</code> function, where it now accepts an argument, <code>b0</code>, to indicate the initial value of <code>b</code>.</p><pre><code>int generate_fib (int b0, int n) {<br> int a = 0;<br> int b = b0;<br> ...<br>} </code></pre><p>Then the <code>extern</code> statement, and the call to <code>generate_fib</code> would have to be updated accordingly.</p><pre><code>extern generate_fib: (int, int) -> int<br><br>lostanza defn call-fib () -> ref<False> :<br> call-c generate_fib(2, 10)<br> return false</code></pre><p>Compiling and running the new program now prints out</p><pre><code>Calling fibonacci<br>2<br>2<br>4<br>6<br>10<br>16<br>26<br>42<br>68<br>110<br>Done calling fibonacci</code></pre><h3 id="anchor388">Declaring a LoStanza Function</h3><p>LoStanza is a small sub-language within Stanza that allows users to precisely specify data layouts and perform low-level hardware operations. LoStanza can be used for writing high performance code, communicating with external peripherals, and implementing system level functions. Stanza's garbage collector, for example, is written in LoStanza. In this chapter, we are using it to interface with externally defined functions. </p><p>The line</p><pre><code>lostanza defn call-fib () -> ref<False></code></pre><p>declares a LoStanza function called <code>call-fib</code>. Its return type, <code>ref<False></code>, indicates that it returns a reference to the Stanza type, <code>False</code>. </p><p>The line</p><pre><code>call-c generate_fib(10)</code></pre><p>calls the <code>generate_fib</code> function with the argument <code>10</code>. The <code>call-c</code> tells Stanza to call <code>generate_fib</code> with the <span style="font-style:italic;">C calling convention</span>. By default, Stanza uses the <span style="font-style:italic;">Stanza calling convention</span> to call other functions, and if you forget the <code>call-c</code> it will seriously confuse <code>generate_fib</code> and crash the program. </p><p>Finally, the line</p><pre><code>return false</code></pre><p>simply returns <code>false</code> to whomever called <code>call-fib</code>.</p><h3 id="anchor389">C Functions that Return void</h3><p>When a C function is declared to return a value of type <code>void</code>, it means that the function is called for its side effects only, and returns an arbitrary value. Let's change <code>generate_fib</code> to return <code>void</code>.</p><pre><code>void generate_fib (int b0, int n) {<br> int a = 0;<br> int b = b0;<br> while(n > 0){<br> int c = a + b;<br> printf("%d\n", c);<br> a = b;<br> b = c;<br> n = n - 1;<br> }<br>}</code></pre><p>Stanza does not provide any explicit support for modeling arbitrary values, so the <code>extern</code> statement would remain as</p><pre><code>extern generate_fib: (int, int) -> int</code></pre><p>and, as the programmer, you would have to remember (or document) that <code>generate_fib</code> returns some random integer that should not be used.</p><h2 id="anchor107">Calling LoStanza from Stanza</h2><p>The arguments to <code>generate_fib</code> are currently hardcoded into the <code>call-fib</code> function. Let's change that to allow both <code>b0</code> and <code>n</code> to be passed as arguments to <code>call-fib</code>.</p><pre><code>extern generate_fib: (int, int) -> int<br><br>lostanza defn call-fib (b0:int, n:int) -> ref<False> :<br> call-c generate_fib(b0, n)<br> return false</code></pre><p>And our test code will now call <code>call-fib</code> with different arguments.</p><pre><code>println("Calling fibonacci(1, 10)")<br>call-fib(1, 10)<br>println("Calling fibonacci(2, 10)")<br>call-fib(2, 10)<br>println("Done calling fibonacci")</code></pre><p>However, attempting to compile the above gives us the following error.</p><pre><code>LoStanza function call-fib of type (int, int) -> ref<False> <br>can only be referred to from LoStanza.</code></pre><p>As mentioned, <code>int</code> is a <span style="font-style:italic;">LoStanza</span> type, and you're not allowed to call it directly from Stanza with <span style="font-style:italic;">Stanza</span> objects.</p><h3 id="anchor390">Convert Stanza Objects to LoStanza Values</h3><p>The type <code>Int</code> is declared like this.</p><pre><code>lostanza deftype Int :<br> value: int</code></pre><p>We will explain what that means in more detail later, but for now, notice that it contains a field called <code>value</code> that is of type <code>int</code>. Thus, we will modify our <code>call-fib</code> function to accept references to <code>Int</code> objects, and then pass their <code>value</code> fields to <code>generate_fib</code>.</p><pre><code>lostanza defn call-fib (b0:ref<Int>, n:ref<Int>) -> ref<False> :<br> call-c generate_fib(b0.value, n.value)<br> return false</code></pre><p>With this change, the program now compiles correctly, and prints out</p><pre><code>Calling fibonacci(1, 10)<br>1<br>1<br>2<br>3<br>5<br>8<br>13<br>21<br>34<br>55<br>Calling fibonacci(2, 10)<br>2<br>2<br>4<br>6<br>10<br>16<br>26<br>42<br>68<br>110<br>Done calling fibonacci</code></pre><p>A LoStanza function can be called from Stanza if and only if all of its argument types and return type are <code>ref<T></code>, indicating that it accepts and returns a reference to a Stanza object. LoStanza functions that can be suitably called from Stanza are indistinguishable from regular Stanza functions. So in addition to being called directly, they can also be passed as arguments, and stored in datastructures.</p><h3 id="anchor391">Convert LoStanza Values to Stanza Objects</h3><p>Let us now change <code>generate_fib</code> to return the <code>n</code>'th fibonacci number, instead of printing all of them. </p><pre><code>int generate_fib (int b0, int n) {<br> int a = 0;<br> int b = b0;<br> while(n > 0){<br> int c = a + b;<br> a = b;<br> b = c;<br> n = n - 1;<br> }<br> return b;<br>}</code></pre><p>We'll also update our <code>call-fib</code> function to return the result of <code>generate_fib</code>.</p><pre><code>lostanza defn call-fib (b0:ref<Int>, n:ref<Int>) -> int :<br> val result = call-c generate_fib(b0.value, n.value)<br> return result</code></pre><p>Here's the updated test code that prints out the result of calling <code>call-fib</code>.</p><pre><code>println("fibonacci(1, 10) =")<br>println(call-fib(1, 10))<br>println("fibonacci(2, 10) =")<br>println(call-fib(2, 10))<br>println("Done calling fibonacci")</code></pre><p>However, attempting to compile the above gives us this familiar error.</p><pre><code>LoStanza function call-fib of type (ref<Int>, ref<Int>) -> int <br>can only be referred to from LoStanza.</code></pre><p>As mentioned already, a LoStanza function can be called from Stanza if and only if all of its argument types <span style="font-style:italic;">and return type</span> are <code>ref<T></code>. We learned how to convert Stanza <code>Int</code> objects into LoStanza <code>int</code> values in the previous section. Now we'll learn how to convert LoStanza <code>int</code> values back into Stanza <code>Int</code> objects.</p><p>To create a Stanza <code>Int</code> object, we use the LoStanza <code>new</code> operator.</p><pre><code>lostanza defn call-fib (b0:ref<Int>, n:ref<Int>) -> ref<Int> :<br> val result = call-c generate_fib(b0.value, n.value)<br> return new Int{result}</code></pre><p>Our test code now compiles and runs, and prints out</p><pre><code>fibonacci(1, 10) =<br>89<br>fibonacci(2, 10) =<br>178<br>Done calling fibonacci</code></pre><p>Note that the LoStanza <code>new</code> operator is completely different than the Stanza <code>new</code> operator. It is best to consider LoStanza as a completely separate language from Stanza. It has its own syntax, operators, and behaviour. The thing that makes LoStanza unique is that there is a well-defined and flexible interface between it and Stanza.</p><h2 id="anchor108">LoStanza Types</h2><p>There are a handful of additional LoStanza types in addition to the <code>int</code> type that we used in the declaration of the <code>generate_fib</code> function. </p><h3 id="anchor392">Primitive Types</h3><p>Here is a listing of the rest of the LoStanza primitive types, along with an example of their values.</p><pre><code>val x:byte = 42Y<br>val x:int = 42<br>val x:long = 42L<br>val x:float = 42.0f<br>val x:double = 42.0</code></pre><p>A <code>byte</code> is an 8-bit unsigned integer. An <code>int</code> is a 32-bit signed integer. A <code>long</code> is a 64-bit signed integer. A <code>float</code> is a 32-bit single precision floating point number. And a <code>double</code> is a 64-bit double precision floating point number.</p><p>The above primitive types have an associated Stanza type, each declared to contain a single <code>value</code> field containing the LoStanza representation of its value. The associated Stanza types for <code>byte</code>, <code>int</code>, <code>long</code>, <code>float</code>, and <code>double</code>, are <code>Byte</code>, <code>Int</code>, <code>Long</code>, <code>Float</code>, and <code>Double</code>, respectively. In addition to <code>Byte</code>, the Stanza type <code>Char</code> is also declared to contain a single <code>value</code> field of type <code>byte</code>.</p><p>As an example, let us write a version of <code>generate_fib</code> that works on double precision floating point numbers.</p><pre><code>double generate_fib_d (double b0, int n) {<br> double a = 0.0;<br> double b = b0;<br> while(n > 0){<br> double c = a + b;<br> a = b;<br> b = c;<br> n = n - 1;<br> }<br> return b;<br>}</code></pre><p>Here is the LoStanza code needed to be able to call <code>generate_fib_d</code> from Stanza.</p><pre><code>extern generate_fib_d: (double, int) -> double<br><br>lostanza defn call-fib (b0:ref<Double>, n:ref<Int>) -> ref<Double> :<br> val result = call-c generate_fib_d(b0.value, n.value)<br> return new Double{result}</code></pre><p>Now armed with double precision floating point, let's calculate the 100'th fibonacci number.</p><pre><code>println("fibonacci(1.0, 100) = ")<br>println(call-fib(1.0, 100))<br>println("fibonacci(2.0, 100) = ")<br>println(call-fib(2.0, 100))<br>println("Done calling fibonacci")</code></pre><p>Compiling and running the above prints out</p><pre><code>fibonacci(1.0, 100) = <br>573147844013817200640.000000000000000<br>fibonacci(2.0, 100) = <br>1146295688027634401280.000000000000000<br>Done calling fibonacci</code></pre><p>Notice that the <code>call-fib</code> function is overloaded to accept both <code>Int</code> and <code>Double</code> arguments. LoStanza functions have all the same features as Stanza functions, and this includes their ability to be overloaded.</p><h3 id="anchor393">Pointer Types</h3><p>Pointers are represented in LoStanza with the <code>ptr<t></code> type. The little <code>t</code> represents any LoStanza type. For example, here is the type representing a pointer to an <code>int</code>,</p><pre><code>ptr<int></code></pre><p>and here is the type representing a <span style="font-style:italic;">pointer to</span> a pointer to an <code>int</code>,</p><pre><code>ptr<ptr<int>></code></pre><p>The type</p><pre><code>ptr<?></code></pre><p>represents a generic pointer to anything.</p><p>As an example of their use, let's call the C <code>malloc</code> and <code>free</code> functions to allocate and delete space for three integers.</p><pre><code>extern malloc: long -> ptr<?><br>extern free: ptr<?> -> int<br><br>lostanza defn try-pointers () -> ref<False> :<br> val ints:ptr<int> = call-c malloc(3 * sizeof(int))<br> call-c free(ints)<br> return false</code></pre><p>The <code>[]</code> operator in LoStanza is the dereference operator and retrieves the value stored at the given pointer address. Here is an example of storing and retrieving values into and from the <code>ints</code> pointer.</p><pre><code>lostanza defn try-pointers () -> ref<False> :<br> val ints:ptr<int> = call-c malloc(3 * sizeof(int))<br> [ints] = 42<br> [ints + 4] = 43<br> [ints + 8] = 44<br> val x = [ints]<br> val y = [ints + 4]<br> val z = [ints + 8]<br> call-c free(ints)<br> return false</code></pre><p>Programmers familiar with C should note that arithmetic on pointers <span style="font-style:italic;">do not</span> automatically operate in terms of the size of the pointer's data type. To retrieve the <code>i</code>'th element from a pointer, assuming that its elements are stored contiguously, we use the following syntax.</p><pre><code>lostanza defn try-pointers () -> ref<False> :<br> val ints:ptr<int> = call-c malloc(3 * sizeof(int))<br> ints[0] = 42<br> ints[1] = 43<br> ints[2] = 44<br> val x = ints[0]<br> val y = ints[1]<br> val z = ints[2]<br> call-c free(ints)<br> return false</code></pre><p>This is equivalent to the previous example.</p><h3 id="anchor394">Declaring a LoStanza Type</h3><p>Consider the following definition of the C type <code>Point3D</code> and function <code>get_origin</code>.</p><pre><code>typedef struct {<br> float x;<br> float y;<br> float z;<br>} Point3D;<br><br>Point3D* get_origin () {<br> Point3D* p = (Point3D*)malloc(sizeof(Point3D));<br> p->x = 0.0f;<br> p->y = 0.0f;<br> p->z = 0.0f;<br> return p;<br>}</code></pre><p><code>Point3D</code> is a struct that contains three <code>float</code> fields, and <code>get_origin</code> returns a pointer to a <code>Point3D</code>. </p><p>Here is how we would declare our own LoStanza type to mirror the C type definition.</p><pre><code>lostanza deftype Point3D :<br> x: float<br> y: float<br> z: float</code></pre><p>Here's a function that demonstrates calling <code>get_origin</code> and returning the <code>x</code> field in the returned point.</p><pre><code>extern get_origin: () -> ptr<Point3D><br><br>lostanza defn origin-x () -> ref<Float> :<br> val p = call-c get_origin()<br> return new Float{p.x}</code></pre><p>Here's some code to test the <code>origin-x</code> function.</p><pre><code>println("The x coordinate of the origin is %_." % [origin-x()])</code></pre><p>which prints out</p><pre><code>The x coordinate of the origin is 0.000000.</code></pre><h3 id="anchor395">Reference Types</h3><p>A reference to a Stanza object is represented with the <code>ref<T></code> type. The big <code>T</code> represents any Stanza type. We've already used the <code>ref<Int></code>, and <code>ref<Float></code> types in our examples. </p><p>Our previous function <code>origin-x</code> returned the <code>x</code> coordinate of the origin. But we would really like to just return the entire point to Stanza. Similar to how we converted <code>int</code> values to <code>Int</code> objects, this is done using the <code>new</code> operator.</p><pre><code>lostanza defn origin () -> ref<Point3D> :<br> val p = call-c get_origin()<br> return new Point3D{p.x, p.y, p.z}</code></pre><p>And here are the LoStanza getter functions for a <code>Point3D</code> that allows Stanza to retrieve the coordinates within it.</p><pre><code>lostanza defn x (p:ref<Point3D>) -> ref<Float> :<br> return new Float{p.x}<br>lostanza defn y (p:ref<Point3D>) -> ref<Float> :<br> return new Float{p.y}<br>lostanza defn z (p:ref<Point3D>) -> ref<Float> :<br> return new Float{p.z}</code></pre><p>Here's some code to test our new <code>origin</code> function.</p><pre><code>val p = origin()<br>println("The x coordinate of the origin is %_." % [x(p)])<br>println("The y coordinate of the origin is %_." % [y(p)])<br>println("The z coordinate of the origin is %_." % [z(p)])</code></pre><p>Compiling and running the above code prints out</p><pre><code>The x coordinate of the origin is 0.000000.<br>The y coordinate of the origin is 0.000000.<br>The z coordinate of the origin is 0.000000.</code></pre><p>As one last example, let's write, in LoStanza, a constructor function for <code>Point3D</code> objects that can be called from Stanza.</p><pre><code>lostanza defn Point3D (x:ref<Float>, y:ref<Float>, z:ref<Float>) -> ref<Point3D> :<br> return new Point3D{x.value, y.value, z.value}</code></pre><p>Here's some test code for trying out our constructor function.</p><pre><code>val p2 = Point3D(1.0f, 3.4f, 4.2f)<br>println("The x coordinate of p2 is %_." % [x(p2)])<br>println("The y coordinate of p2 is %_." % [y(p2)])<br>println("The z coordinate of p2 is %_." % [z(p2)])</code></pre><p>which, when compiled and ran, prints out</p><pre><code>The x coordinate of p2 is 1.000000.<br>The y coordinate of p2 is 3.400000.<br>The z coordinate of p2 is 4.200000.</code></pre><p>With these definitions, <code>Point3D</code> becomes a type that we can freely manipulate from Stanza. We can create <code>Point3D</code> objects, and we can retrieve its fields. </p><h3 id="anchor396">Literal Strings</h3><p>A literal string in LoStanza has type <code>ptr<byte></code> and refers to a pointer to a memory location where the ascii byte representation of its characters are stored. </p><p>For example, the following snippet will retrieve the ascii byte value of the character <code>'o'</code> and store it in the value <code>c</code>.</p><pre><code>val str:ptr<byte> = "Hello"<br>val c:byte = str[4]</code></pre><p>The characters are also stored with a terminating zero byte after all the characters. This allows the literal strings to be suitably used with external libraries expecting C language strings.</p><h3 id="anchor397">External Unknown Arity Functions</h3><p>Neither LoStanza nor Stanza supports the definition of functions that take an unknown number of arguments. But there are external libraries containing such functions. The C <code>printf</code> function is the most famous one.</p><p>The <code>printf</code> function would be declared like this.</p><pre><code>extern printf: (ptr<byte>, ? ...) -> int</code></pre><p>Here is an example of calling it from a function called <code>test</code>.</p><pre><code>lostanza defn test () -> ref<False> :<br> call-c printf("The friendship between %s and %s is valued at over %d.\n",<br> "Timon", "Pumbaa", 9000)<br> return false<br><br>test()</code></pre><p>Compiling and running the above prints out</p><pre><code>The friendship between Timon and Pumbaa is valued at over 9000.</code></pre><h2 id="anchor109">External Global Variables</h2><p>Let us suppose that <code>generate_fib</code> was written differently. Suppose that it does not accept any arguments, and also returns <code>void</code>. Instead it will retrieve its argument from a global variable named <code>FIB_PARAM</code>, and store the result in <code>FIB_PARAM</code> when finished. </p><pre><code>int FIB_PARAM;<br><br>void generate_fib (void) {<br> int a = 0;<br> int b = 1;<br> while(FIB_PARAM > 0){<br> int c = a + b;<br> a = b;<br> b = c;<br> FIB_PARAM = FIB_PARAM - 1;<br> }<br> FIB_PARAM = b;<br>}</code></pre><p>To call the new <code>generate_fib</code>, our LoStanza <code>call-fib</code> function would need to be able to read and write to the <code>FIB_PARAM</code> variable. Here's how to do that.</p><pre><code>extern FIB_PARAM : int<br>extern generate_fib : () -> int<br><br>lostanza defn call-fib (n:ref<Int>) -> ref<Int> :<br> FIB_PARAM = n.value<br> call-c generate_fib()<br> return new Int{FIB_PARAM}<br><br>println("fib(10) = %_" % [call-fib(10)])</code></pre><p>Compiling and running the above prints out</p><pre><code>fib(10) = 89</code></pre><h2 id="anchor110">Function Pointers</h2><p>Certain C libraries tend to make heavy use of function pointers for implementing callbacks or parameterized behaviour. Let us suppose there is a C function called <code>choose_greeting</code> that when given an integer argument returns one of several possible greeting functions to return. These greeting functions then accept a C string and print out an appropriate message.</p><pre><code>void standard_greeting (char* name) {<br> printf("Hello %s!\n", name);<br>}<br><br>void chill_greeting (char* name) {<br> printf("'Sup %s.\n", name);<br>}<br><br>void excited_greeting (char* name) {<br> printf("%c", name[0]);<br> for(int i=0; i<5; i++)<br> printf("%c", name[1]);<br> printf("%s! Heyyyy!\n", name+2); <br>}<br><br>typedef void (*Greeting)(char* name);<br>Greeting choose_greeting (int option) {<br> switch(option){<br> case 1: return &chill_greeting;<br> case 2: return &excited_greeting;<br> default: return &standard_greeting;<br> }<br>}</code></pre><p>The <code>extern</code> declaration for <code>choose_greeting</code> would look like this.</p><pre><code>extern choose_greeting: int -> ptr<(ptr<byte> -> int)></code></pre><p>Here's how to decipher that piece by piece. The returned greeting functions all have type</p><pre><code>ptr<byte> -> int</code></pre><p>The <code>choose_greeting</code> function returns a <span style="font-style:italic;">pointer</span> to a greeting function. So the return type of <code>choose_greeting</code> is</p><pre><code>ptr<(ptr<byte> -> int)></code></pre><p>And <code>choose_greeting</code>, itself, requires an integer argument. Thus the full type for <code>choose_greeting</code> is</p><pre><code>int -> ptr<(ptr<byte> -> int)></code></pre><p>Here is the LoStanza <code>greet</code> function which takes an integer argument called <code>option</code> and greets Patrick appropriately.</p><pre><code>lostanza defn greet (option:ref<Int>) -> ref<False> :<br> val greet = call-c choose_greeting(option.value)<br> call-c [greet]("Patrick")<br> return false</code></pre><p>Notice that the value <code>greet</code> has type <code>ptr<(ptr<byte> -> int)></code>, and thus it needs to be first dereferenced before it can be called.</p><pre><code>call-c [greet]("Patrick")</code></pre><p>Let's try it out!</p><pre><code>println("Option 0")<br>greet(0)<br><br>println("\nOption 1")<br>greet(1)<br><br>println("\nOption 2")<br>greet(2)</code></pre><p>Compiling and running the above prints out</p><pre><code>Option 0<br>Hello Patrick!<br><br>Option 1<br>'Sup Patrick.<br><br>Option 2<br>Paaaaatrick! Heyyyy!</code></pre><h2 id="anchor111">The Address Operator</h2><p>The <code>greet</code> function in the previous example accepts an integer argument to select the type of greeting, but it only ever greets Patrick. Let's generalize <code>greet</code> to accept whom to greet as well.</p><p>We want <code>greet</code> to be callable from Stanza, so the name will be passed in as a <code>String</code> object.</p><pre><code>lostanza defn greet (option:ref<Int>, name:ref<String>) -> ref<False> :<br> ...</code></pre><p>But the <code>greet</code> function requires a <code>ptr<byte></code> as its argument, and <code>name</code> is a <code>ref<String></code>. How do we get access to a pointer to the string's characters?</p><p>The <code>String</code> type is declared in the core library as</p><pre><code>lostanza deftype String :<br> length: long<br> hash: int<br> chars: byte ...</code></pre><p>The ellipsis following the <code>byte</code> indicates that the <code>String</code> object ends with a variable number of trailing <code>byte</code> values. We need a pointer to those values to call <code>greet</code> with. To do that we will use the <code>addr</code> operator, which will return the pointer address of a location.</p><p>Let's now write our <code>greet</code> function with the <code>addr</code> operator.</p><pre><code>lostanza defn greet (option:ref<Int>, name:ref<String>) -> ref<False> :<br> val greet = call-c choose_greeting(option.value)<br> call-c [greet](addr(name.chars))<br> return false</code></pre><p>And update our test code to pass in a different name for each type of greeting.</p><pre><code>println("Option 0")<br>greet(0, "Emmy")<br><br>println("\nOption 1")<br>greet(1, "Patrick")<br><br>println("\nOption 2")<br>greet(2, "Luca")</code></pre><p>Attempting to compile the above, however, gives us this error.</p><pre><code>Cannot retrieve address of unstable location using addr operator.</code></pre><p>What does that mean?</p><h3 id="anchor398">Stable and Unstable Locations</h3><p>Underneath the hood, Stanza uses a precise <span style="font-style:italic;">relocating</span> garbage collector. What this means is that objects are constantly being shuffled around in memory during the garbage collection process. An unstable location is a location whose address is not fixed, such as a field in a Stanza object. In contrast, a stable location is one whose address is fixed, such as a piece of memory allocated using <code>malloc</code>.</p><p>The error above is saying that we cannot use the <code>addr</code> operator to retrieve the address of <code>name.chars</code>, which is an unstable location. <code>name</code> is a Stanza string and will be relocated whenever the garbage collector runs, and so the address of <code>name.chars</code> is constantly changing. </p><p>However, we are planning to pass the address of <code>name.chars</code> to C and then <span style="font-style:italic;">immediately</span> start executing C code. Additionally, the C function is guaranteed not to hang onto the pointer after it returns. Thus, in this particular case, we know that Stanza's garbage collector will never have a chance to run, and it <span style="font-style:italic;">is</span> safe to retrieve the pointer of <code>name.chars</code>.</p><p>To <span style="font-style:italic;">force</span> Stanza to give you the address of an unstable location, Stanza provides you the <code>addr!</code> operator. So let's update our <code>greet</code> function by using the <code>addr!</code> operator this time,</p><pre><code>lostanza defn greet (option:ref<Int>, name:ref<String>) -> ref<False> :<br> val greet = call-c choose_greeting(option.value)<br> call-c [greet](addr!(name.chars))<br> return false</code></pre><p>and try compiling and running the program again. The program now prints out</p><pre><code>Option 0<br>Hello Emmy!<br><br>Option 1<br>'Sup Patrick.<br><br>Option 2<br>Luuuuuca! Heyyyy!</code></pre><p>You should stick to using the <code>addr</code> operator whenever you can, and use the <code>addr!</code> operator only when you're <span style="font-style:italic;">very</span> sure that the object won't be relocated while you're using the pointer.</p><h2 id="anchor112">Calling LoStanza from C</h2><p>So far we've only considered calling C functions from Stanza, but what if you wanted to call a Stanza function from C? Stanza supports both directions of calling and this section will explain how.</p><p>Let us reconsider the <code>generate_fib</code> function again. This time, we will have <code>generate_fib</code> call a Stanza function for each number that is generated. Here is the code for <code>generate_fib</code>.</p><pre><code>#include<stdio.h><br>#include<stdlib.h><br><br>void number_generated (int x);<br><br>void generate_fib (int n) {<br> int a = 0;<br> int b = 1;<br> while(n > 0){<br> number_generated(b);<br> int c = a + b;<br> a = b;<br> b = c;<br> n = n - 1;<br> }<br>}</code></pre><p>Notice that we assume the existence of a function called <code>number_generated</code> that we can call from C.</p><p>C will call <code>number_generated</code> using the C calling convention, so we need to be able to define a LoStanza function that is expecting to be called with the C calling convention. The <code>extern</code> keyword will allow us to do that. Our <code>number_generated</code> function will push the generated number to a global vector called <code>FIB_NUMBERS</code>.</p><pre><code>val FIB_NUMBERS = Vector<Int>()<br><br>extern defn number_generated (n:int) -> int :<br> add(FIB_NUMBERS, new Int{n})<br> return 0</code></pre><p>The implementation of the <code>call-fib</code> function remains as it was before.</p><pre><code>extern generate_fib: int -> int<br><br>lostanza defn call-fib (n:ref<Int>) -> ref<False> :<br> call-c generate_fib(n.value)<br> return false</code></pre><p>Let's try it out then! Here's our test code.</p><pre><code>call-fib(20)<br>println("Generated Numbers: %_" % [FIB_NUMBERS])</code></pre><p>Compiling and running the above prints out</p><pre><code>Generated Numbers: [1 1 2 3 5 8 13 21 34 55 89 144 233<br> 377 610 987 1597 2584 4181 6765]</code></pre><h2 id="anchor113">Passing Callbacks to C</h2><p>In the last section, we showed you how to write a LoStanza function that can be called with C. However, C libraries are not typically architected to directly call a named user function. Instead, the user will pass the library a pointer to a callback function that is then later called by the library. </p><p>Let's change our <code>generate_fib</code> function so that it no longer directly calls the <code>number_generated</code> function. It will accept instead, as an argument, a pointer to a callback function which it will call. </p><pre><code>void generate_fib (int n, void (*number_generated)(int x)) {<br> int a = 0;<br> int b = 1;<br> while(n > 0){<br> number_generated(b);<br> int c = a + b;<br> a = b;<br> b = c;<br> n = n - 1;<br> }<br>}</code></pre> <p>We shall keep the LoStanza definition of <code>number_generated</code> the same, but we will need to change the declaration of the <code>generate_fib</code> function, and also pass a pointer to <code>number_generated</code> to the call to <code>generate_fib</code>.</p><pre><code>extern generate_fib: (int, ptr<(int -> int)>) -> int<br><br>lostanza defn call-fib (n:ref<Int>) -> ref<False> :<br> call-c generate_fib(n.value, addr(number_generated))<br> return false</code></pre><p>Notice the use of the standard <code>addr</code> operator for retrieving the address of the <code>number_generated</code> function.</p><p>Compiling and running the above prints out</p><pre><code>Generated Numbers: [1 1 2 3 5 8 13 21 34 55 89 144 233<br> 377 610 987 1597 2584 4181 6765]</code></pre><p>Let's take this time to review everything that this example demonstrates.</p><ol><li>Stanza is calling <code>call-fib</code>, which is a function written in LoStanza.
</li><li> <code>call-fib</code> is calling <code>generate_fib</code>, which is a function written in C.
</li><li> <code>generate_fib</code> is passed a pointer to the <code>number_generated</code> function which is written in LoStanza.
</li><li> <code>generate_fib</code> runs and calls <code>number_generated</code> multiple times.
</li><li>Each time <code>number_generated</code> is called, it creates a Stanza <code>Int</code> object from the argument passed to it by <code>generate_fib</code>, and calls the Stanza function <code>add</code> to push it onto a vector.
</li></ol><p>This will likely be the most complicated usage of Stanza's foreign function interface you will come across, but it's nice to know that the flexibility is there when you need it.</p>
</td>
<td class="rest">
<img url="resources/spacer.gif"></img>
</td>
</tr>
<tr><td colspan="3" class="footer">
Site design by Luca Li. Copyright 2015.
</td></tr>
</table>
</body>
</html>