Dylan allows you to create new control constructs and other high-level
forms. They can be used to automatically release resources, simplify class
creation, or adapt Dylan for a specific problem domain.

In the following example, we create a with-mutex statement
that automatically acquires and releases a POSIX mutex. Once again, we
import the necessary functions from C.

Dylan macros are part of the compiler, not a preprocessor. This means
that they can pay attention to the grammar of the language. They’re also
hygienic, which means they can’t suffer name clashes with
surrounding code. (In the example below, mutex in the macro
expansion would not be seen by the expressions in ?code.)

define interface
  #include "pthread.h",
    import: {"pthread_mutex_t",
	     "pthread_mutex_init",
	     "pthread_mutex_destroy",
	     "pthread_mutex_lock",
	     "pthread_mutex_unlock"};
end interface;

define function check-error(errno :: <integer>) => ()
  if (errno < 0)
    error("POSIX error %d occured in pthreads wrapper", errno);
  end if;
end function;

define macro with-mutex
  { with-mutex (?mutex:expression) ?code:body end }
    => { let mutex = ?mutex;
	 check-error(pthread-mutex-lock(mutex));
	 block ()
	   ?code
	 cleanup
	   check-error(pthread-mutex-unlock(mutex));
	 end block; }
end with-mutex;

define variable mutex = make(<pthread-mutex-t>);
check-error(pthread-mutex-init(mutex, null-pointer));

with-mutex (mutex)
  format(*standard-output*, "The mutex is locked.\n");
end;

check-error(pthread-mutex-destroy(mutex));