Note: This website is archived. For up-to-date information about D projects and development, please visit wiki.dlang.org.

Changes between Version 4 and Version 5 of API/Part1

Show
Ignore:
Author:
JarrettBillingsley (IP: 65.117.184.122)
Timestamp:
08/02/07 14:14:00 (17 years ago)
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • API/Part1

    v4 v5  
    1 = Part 1
     1= Exchanging Values and Calling Functions
    22 
    33== The Stack (and using values directly) == 
    125125Default parameters are easy too.  Just create a local variable, and if there are enough parameters, assign it the value of the corresponding parameter; otherwise just assign it your default value. 
    126126 
    127 === Calling functions (and classes, and objects, and threads, and...) === 
     127== Calling functions (and classes, and objects, and threads, and...) == 
    128128 
    129129Not only do you use the stack for getting parameters to and returning values from your own functions, but you also use it for passing parameters to and getting return values from other functions.  But you don't only call functions.  You can call classes to instantiate them, you can call objects if they overload the opCall metamethod, and you can call coroutine threads to resume them.  All of these are handled the same way, and parallel the way you do them in MiniD. 
    261261 
    262262callMethod is very straightforward.  It takes the object to call the method on (which will also be used as the 'this' pointer of course), the name of the method to call, the number of returns, and then a list of parameters.  This code will display "A.foo 5, 10" when run. 
     263 
     264== Handling Errors == 
     265 
     266Error handling in C is a joke.  You either have to check return codes, or use a setjmp/longjmp protocol, or check a global errno or something equally tedious and ugly.  In D, we have exceptions.  In MiniD, we also have exceptions.  Actually, as far as the implementation is concerned, these are one and the same. 
     267 
     268When MiniD code throws an exception, on the native side it really does throw an exception as well (one derived from MDException, to be exact).  The interpreter does some catching and rethrowing trickery to unwind the script call stack, but when it hits a native call, it rethrows the exception to allow native code to catch it.  When native code throws an exception, the exact same mechanism is used.  This means that any exceptions that script code throws can be caught by native code and vice versa.  Isn't that nice? 
     269 
     270The interpreter will only bother with exceptions derived from MDException, however.  If some other exception occurs, such as an exception in a native library function, or an out of memory error, stack overflow, access violation etc.  it will skip over the exception handlers in the interpreter.  This is good in most cases, but sometimes you don't want this to happen, such as when you're writing a library wrapper for a native library to expose code to MiniD.  In this case, you usually want to translate any non-MiniD exceptions into MiniD exceptions.  For this, MDState provides the safeCode method. 
     271 
     272safeCode takes a lazy expression of any type.  It evaluates that expression, and returns its result.  However, if the expression throws a MiniD exception, safeCode will rethrow it, and if the expression throws a non-MiniD exception, safeCode will throw a new MiniD exception whose message is the result of the thrown exception's .toUtf8() method.  This way, you can wrap calls to native calls which can throw an exception in safeCode, and any exceptions it throws will be catchable by MiniD code. 
     273 
     274As an example, here is the implementation of the string.toInt function in the standard library. 
     275 
     276{{{ 
     277#!d 
     278int toInt(MDState s, uint numParams) 
     279{ 
     280        dchar[] src = s.getContext!(dchar[]); 
     281 
     282        int base = 10; 
     283 
     284        if(numParams > 0) 
     285                base = s.getParam!(int)(0); 
     286 
     287        s.push(s.safeCode(Integer.toInt(src, base))); 
     288        return 1; 
     289} 
     290}}} 
     291 
     292You'll notice a new function -- getContext -- in there.  That gets the context parameter which was passed to this function.  This is how you write methods in native code.  The string library is set as the type metatable for strings, and so when you call toInt on a string object, the string on which it was called is passed as the context, which we then retrieve in a similar way to any other parameter.   
     293 
     294The optional base parameter is retrieved next, and then it calls the Integer (really tango.text.convert.Integer) toInt function with the string and the base.  Note the use of safeCode wrapped around that expression.  Integer.toInt can throw exceptions if there is a formatting error or so, and so we use safeCode to ensure that any exceptions that it throws are converted to MiniD exceptions.