With nothrow and @nogc annotations, we've been motivated to add these annotations to C system API functions, because obviously such functions aren't going to throw D exceptions or call the D garbage collector.

But this exposed a problem - functions like C's qsort() take a pointer to a callback function. The callback function, being supplied by the D programmer, may throw and may call the garbage collector. By requiring the callback function to be also nothrow @nogc, this is an unreasonable requirement besides breaking most existing D code that uses qsort().

This problem applies as well to the Windows APIs and the Posix APIs with 
callbacks.

The solution is to use overloading so that if your callback is nothrow, it will call the nothrow version of qsort, if it is throwable, it calls the throwable version of qsort.

Never mind that those two versions of qsort are actually the same function (!), even though D's type system regards them as different. Although this looks like an usafe hack, it actually is quite safe, presuming that the rest of the qsort code itself does not throw. This technique relies on the fact that extern(C) functions do not get their types mangled into the names.

Some example code:

  extern (C)         { alias int function() fp_t; }
  extern (C) nothrow { alias int function() fpnothrow_t; }

  extern (C)         int foo(int a, fp_t fp);
  extern (C) nothrow int foo(int a, fpnothrow_t fp);

  extern (C)         int bar();
  extern (C) nothrow int barnothrow();

  void test() {
    foo(1, &bar);         // calls the 'throwing' foo()
    foo(1, &barnothrow);  // calls the 'nothrow' foo()
  }

Reply via email to