diff --git a/include/fmpi_futhark.h b/include/fmpi_futhark.h
deleted file mode 100644
index c7bf37d886e79064f765f971f712a5a71c807128..0000000000000000000000000000000000000000
--- a/include/fmpi_futhark.h
+++ /dev/null
@@ -1,71 +0,0 @@
-// SPDX-License-Identifier: 0BSD
-/*!
- * @file
- * @license{
- * BSD Zero Clause License
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
- * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
- * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
- * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
- * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
- * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- * PERFORMANCE OF THIS SOFTWARE.
- * }
- */
-/*==============================================================================
-    GUARD
-==============================================================================*/
-#ifndef FMPI_FUTHARK_H_20211219234207
-#define FMPI_FUTHARK_H_20211219234207
-/*==============================================================================
-    INCLUDE
-==============================================================================*/
-// C Standard Library
-// External
-// Internal
-#include "internal/fmpi_futhark_internal.h"
-/*==============================================================================
-    STRUCT
-==============================================================================*/
-struct fmpi_ctx;
-/*==============================================================================
-    PUBLIC FUNCTION
-==============================================================================*/
-int fmpi_futhark_init(struct fmpi_ctx * const ctx);
-void fmpi_futhark_exit(struct fmpi_ctx * const ctx);
-void fmpi_futhark_sync(struct fmpi_ctx * const ctx);
-/*------------------------------------------------------------------------------
-    fmpi_futhark_has_error()
-------------------------------------------------------------------------------*/
-/**
- * Check if the last function called before calling
- * fmpi_has_futhark_error() generated an error.
- *
- * @param[in,out] ctx       : Pointer to a fmpi_ctx structure.
- * @param[in]     err_id    : Error id returned by a futhark function.
- * @param[in]     func_name : Function name.
- *
- * @return
- * - `true` if an error is detected.
- * - `false` if no error was detected.
- *
- * @warning
- * - \p{ctx} must be a valid pointer allocated with fmpi_init().
- * - \p{func_name} must not be `NULL`.
- */
-_Bool fmpi_futhark_has_error(struct fmpi_ctx * const ctx, const char * const func_name);
-void fmpi_futhark_abort_on_error(struct fmpi_ctx * ctx, const char * const func_name);
-
-#define fmpi_new_1d(ctx, array, length)                       \
-    FMPI_GENERIC_FUNC_FUTHARK(array, new, 1d, FMPI_FUTHARK_TYPES)(ctx, array, length)
-
-#define fmpi_free_1d(ctx, array, length)                       \
-    FMPI_GENERIC_FUNC_FUTHARK(array, free, 1d, FMPI_FUTHARK_TYPES)(ctx, array)
-/*==============================================================================
-    GUARD
-==============================================================================*/
-#endif // FMPI_FUTHARK_H_20211219234207
diff --git a/include/internal/fmpi_futhark.h b/include/internal/fmpi_futhark.h
new file mode 100644
index 0000000000000000000000000000000000000000..c2b7e21306aac21b673164e4e510daf65dd8b6b0
--- /dev/null
+++ b/include/internal/fmpi_futhark.h
@@ -0,0 +1,180 @@
+// SPDX-License-Identifier: 0BSD
+/*!
+ * @file
+ * @license{
+ * BSD Zero Clause License
+ *
+ * Copyright (c) 2022 by Raphael Bach
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ * }
+ */
+/*==============================================================================
+    GUARD
+==============================================================================*/
+#ifndef FMPI_FUTHARK_H_20211219234207
+#define FMPI_FUTHARK_H_20211219234207
+/*==============================================================================
+    INCLUDE
+==============================================================================*/
+// C Standard Library
+// Internal
+#include "fmpi_error.h"
+#include "generic/fmpi_futhark_generic.h"
+/*==============================================================================
+    STRUCT
+==============================================================================*/
+/*------------------------------------------------------------------------------
+    fmpi_futhark_ctx()
+------------------------------------------------------------------------------*/
+/**
+ * TODO
+ *
+ * @example{
+ *  TODO
+ * }
+ */
+typedef struct fmpi_futhark_ctx {
+    struct futhark_context * ctx;                  //!< TODO
+    struct futhark_context_config * cfg;           //!< TODO
+    const struct fmpi_error_handler * err_handler; //!< TODO
+} fmpi_futhark_ctx;
+/*==============================================================================
+    PUBLIC FUNCTION
+==============================================================================*/
+/*------------------------------------------------------------------------------
+    fmpi_futhark_init()
+------------------------------------------------------------------------------*/
+/**
+ * TODO
+ *
+ * @param[in] err_handler : TODO
+ *
+ * @return
+ * - @success: TODO
+ * - @failure: TODO
+ *
+ * @warning TODO
+ *
+ * @example{
+ *  TODO
+ * }
+ */
+struct fmpi_futhark_ctx * fmpi_futhark_init(const struct fmpi_error_handler * err_handler);
+/*------------------------------------------------------------------------------
+    fmpi_futhark_exit()
+------------------------------------------------------------------------------*/
+/**
+ * TODO
+ *
+ * @param[in] ctx : TODO
+ *
+ * @return
+ * - @success: TODO
+ * - @failure: TODO
+ *
+ * @warning TODO
+ *
+ * @example{
+ *  TODO
+ * }
+ */
+int fmpi_futhark_exit(struct fmpi_futhark_ctx ** ctx);
+/*------------------------------------------------------------------------------
+    fmpi_futhark_sync()
+------------------------------------------------------------------------------*/
+/**
+ * TODO
+ *
+ * @param[in] ctx : TODO
+ *
+ * @return
+ * - @success: TODO
+ * - @failure: TODO
+ *
+ * @warning TODO
+ *
+ * @example{
+ *  TODO
+ * }
+ */
+int fmpi_futhark_sync(const struct fmpi_futhark_ctx * ctx);
+/*------------------------------------------------------------------------------
+    fmpi_futhark_has_error()
+------------------------------------------------------------------------------*/
+/**
+ * Check if the last function called before calling
+ * fmpi_has_futhark_error() generated an error.
+ *
+ * @param[in,out] ctx   : Pointer to a fmpi_ctx structure.
+ * @param[in]     func  : Function name.
+ *
+ * @return
+ * - `true` if an error is detected.
+ * - `false` if no error was detected.
+ *
+ * @warning
+ * - \p{ctx} must be a valid pointer allocated with fmpi_init().
+ * - \p{func} must not be `NULL`.
+ */
+_Bool fmpi_futhark_check_error(const struct fmpi_futhark_ctx * ctx, const char * func);
+/*==============================================================================
+   MACRO
+==============================================================================*/
+/*------------------------------------------------------------------------------
+    fmpi_futhark_init()
+------------------------------------------------------------------------------*/
+/**
+ * TODO
+ *
+ * @param[in] ctx : TODO
+ * @param[in] array : TODO
+ * @param[in] length : TODO
+ *
+ * @return
+ * - @success: TODO
+ * - @failure: TODO
+ *
+ * @warning TODO
+ *
+ * @example{
+ *  TODO
+ * }
+ */
+#define fmpi_futhark_new_1d(ctx, array, length) \
+    FMPI_GENERIC_FUNC(array, new_1d, FMPI_FUTHARK_TYPES)(ctx, array, length)
+/*------------------------------------------------------------------------------
+    fmpi_futhark_init()
+------------------------------------------------------------------------------*/
+/**
+ * TODO
+ *
+ * @param[in] ctx : TODO
+ * @param[in] array : TODO
+ * @param[in] length : TODO
+ *
+ * @return
+ * - @success: TODO
+ * - @failure: TODO
+ *
+ * @warning TODO
+ *
+ * @example{
+ *  TODO
+ * }
+ */
+#define fmpi_futhark_free_1d(ctx, array, length) \
+    FMPI_GENERIC_FUNC(array, free_1d, FMPI_FUTHARK_TYPES)(ctx, array)
+/*==============================================================================
+    GUARD
+==============================================================================*/
+#endif // FMPI_FUTHARK_H_20211219234207
diff --git a/include/internal/fmpi_futhark_internal.h b/include/internal/generic/fmpi_futhark_generic.h
similarity index 58%
rename from include/internal/fmpi_futhark_internal.h
rename to include/internal/generic/fmpi_futhark_generic.h
index 824c88b8f70512979357bb52e66aecc97993e388..4e112f2107599fd18e559bef8af6a4acf35d0e57 100644
--- a/include/internal/fmpi_futhark_internal.h
+++ b/include/internal/generic/fmpi_futhark_generic.h
@@ -4,6 +4,8 @@
  * @license{
  * BSD Zero Clause License
  *
+ * Copyright (c) 2022 by Raphael Bach
+ *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted.
  *
@@ -24,35 +26,29 @@
 /*==============================================================================
     INCLUDE
 ==============================================================================*/
+// C Standard Library
+#include <stddef.h> // size_t
 // Internal
-#include "fmpi_ctx.h"
 #include "fmpi_generic.h"
 /*==============================================================================
     MACRO
 ==============================================================================*/
+struct fmpi_ctx;
+
 #define FMPI_FUTHARK_TYPES \
     FMPI_TYPE_REAL
 
-#define FMPI_PROTO_NEW_1D(T)                                             \
-    struct futhark_##T##_1d * fmpi_new_##T##_1d(struct fmpi_ctx * ctx, const T * array, int length)
-#define FMPI_PROTO_NEW_2D(T)                                             \
-    struct futhark_##T##_2d * fmpi_new_##T##_2d(struct fmpi_ctx * ctx, const T * array, int length)
-#define FMPI_PROTO_NEW_3D(T)                                             \
-    struct futhark_##T##_3d * fmpi_new_##T##_3d(struct fmpi_ctx * ctx, const T * array, int length)
-
-#define FMPI_PROTO_FREE_1D(T)                                            \
-    void fmpi_free_##T##_1d(struct fmpi_ctx * ctx, struct futhark_##T##_1d * array)
-#define FMPI_PROTO_FREE_2D(T)                                            \
-    void fmpi_free_##T##_2d(struct fmpi_ctx * ctx, struct futhark_##T##_2d * array)
-#define FMPI_PROTO_FREE_3D(T)                                            \
-    void fmpi_free_##T##_3d(struct fmpi_ctx * ctx, struct futhark_##T##_3d * array)
+#define FMPI_FUTHARK_DECLARATION(D, T) \
+struct futhark_##T##_##D##d * fmpi_futhark_new_##D##d_##T( \
+    const struct fmpi_ctx * ctx, const T * array, size_t length \
+); \
+void fmpi_futhark_free_##D##d_##T( \
+    const struct fmpi_ctx * ctx, struct futhark_##T##_##D##d * array \
+)
 
-FMPI_DECLARE_FUNC(
-    FMPI_PROTO_NEW_1D, FMPI_FUTHARK_TYPES
-);
-FMPI_DECLARE_FUNC(
-    FMPI_PROTO_FREE_1D, FMPI_FUTHARK_TYPES
-);
+FMPI_DECLARE_DIM_FUNCS(FMPI_FUTHARK_DECLARATION, 1, FMPI_FUTHARK_TYPES);
+FMPI_DECLARE_DIM_FUNCS(FMPI_FUTHARK_DECLARATION, 2, FMPI_FUTHARK_TYPES);
+FMPI_DECLARE_DIM_FUNCS(FMPI_FUTHARK_DECLARATION, 3, FMPI_FUTHARK_TYPES);
 /*==============================================================================
     GUARD
 ==============================================================================*/
diff --git a/src/fmpi_futhark.c b/src/fmpi_futhark.c
index b3d84d4c8fa00fef864bff3a8da1b8d7404289a2..874c91fe620ee8749ac9aae6a4f890fbcd02071b 100644
--- a/src/fmpi_futhark.c
+++ b/src/fmpi_futhark.c
@@ -4,6 +4,8 @@
  * @license{
  * BSD Zero Clause License
  *
+ * Copyright (c) 2022 by Raphael Bach
+ *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted.
  *
@@ -20,126 +22,133 @@
     INCLUDE
 ==============================================================================*/
 // Own header
-#include "fmpi_futhark.h"
+#include "internal/fmpi_futhark.h"
 // C Standard Library
 #include <assert.h>
-#include <stdint.h>
-#include <stdio.h>
+#include <stdbool.h>
+#include <stdint.h> // int64_t
 #include <stdlib.h>
-#include <string.h>
-// External
 // Internal
-#include "fmpi_ctx.h"
-#include "fmpi_mpi.h"
-#include "internal/fmpi_fut.h"
-#include "internal/fmpi_generic.h"
+#include "internal/fmpi_ctx.h"
+#include "internal/fmpi_futhark_entry.h"
+#include "internal/generic/fmpi_generic.h"
 /*==============================================================================
-    STRUCT
+    MACRO
 ==============================================================================*/
+#define FMPI_RAISE_FUTHARK_ERROR(ctx, ...) \
+do { \
+    if((ctx)->err_handler != NULL) { \
+        FMPI_RAISE_ERROR((ctx)->err_handler, "FUTHARK", __VA_ARGS__); \
+    } \
+} while(0)
 /*==============================================================================
     PUBLIC FUNCTION
 ==============================================================================*/
 /*------------------------------------------------------------------------------
     fmpi_futhark_init()
 ------------------------------------------------------------------------------*/
-int fmpi_futhark_init(struct fmpi_ctx * const ctx)
-{
-    assert(ctx != NULL);
-    assert(ctx->futhark == NULL);
-    assert(ctx->futhark_cfg == NULL);
-
-    ctx->futhark_cfg = futhark_context_config_new();
-    if(ctx->futhark_cfg == NULL) {
-        fprintf(stderr, "[FUTHARK ERROR rank=%d] futhark_context_config_new() failed!\n", ctx->mpi->rank);
-        return ctx->mpi->futhark_err_class;
+struct fmpi_futhark_ctx * fmpi_futhark_init(
+    const struct fmpi_error_handler * const err_handler
+){
+    struct fmpi_futhark_ctx * ctx = malloc(sizeof(*ctx));
+    if(ctx == NULL) {
+        if(err_handler != NULL) {
+            FMPI_RAISE_ERROR(err_handler, "FUTHARK", "malloc(fmpi_futhark_ctx) failed!");
+        }
+        return NULL;
+    }
+    ctx->err_handler = (err_handler != NULL) ? err_handler : NULL;
+    ctx->cfg = futhark_context_config_new();
+    if(ctx->cfg == NULL) {
+        FMPI_RAISE_FUTHARK_ERROR(ctx, "futhark_context_config_new() failed!");
+        return ctx;
+    }
+    ctx->ctx = futhark_context_new(ctx->cfg);
+    // The doc says in case of error futhark_context_free() should be called
+    // anyway, implying that futhark_context_new() returns a non-null pointer
+    // even on error.
+    // The code generated by futhark 0.22 says otherwise by clearly returning
+    // NULL if malloc() fails.
+    if(ctx->ctx == NULL) {
+        FMPI_RAISE_FUTHARK_ERROR(ctx, "futhark_context_new() failed!");
+        futhark_context_config_free(ctx->cfg);
+        return ctx;
     }
-    ctx->futhark = futhark_context_new(ctx->futhark_cfg);
-    char * err_ptr = futhark_context_get_error(ctx->futhark);
-    if(ctx->futhark == NULL || err_ptr != NULL) {
-        const char * err_str = err_ptr != NULL ? err_ptr : "";
-        fprintf(stderr, "[FUTHARK ERROR rank=%d] futhark_context_new() failed! %s\n", ctx->mpi->rank, err_str);
-        futhark_context_free(ctx->futhark);
-        futhark_context_config_free(ctx->futhark_cfg);
-        free(ctx->futhark);
-        return ctx->mpi->futhark_err_class;
+    if(fmpi_futhark_check_error(ctx, "futhark_context_new") == true) {
+        fmpi_futhark_sync(ctx);
+        futhark_context_free(ctx->ctx);
+        futhark_context_config_free(ctx->cfg);
     }
-    return MPI_SUCCESS;
+    return ctx;
 }
 /*------------------------------------------------------------------------------
     fmpi_futhark_exit()
 ------------------------------------------------------------------------------*/
-void fmpi_futhark_exit(struct fmpi_ctx * const ctx)
+int fmpi_futhark_exit(struct fmpi_futhark_ctx ** const ctx)
 {
     assert(ctx != NULL);
-    assert(ctx->futhark_cfg != NULL);
-    assert(ctx->futhark != NULL);
+    assert(*ctx != NULL);
 
-    fmpi_futhark_sync(ctx);
-    futhark_context_free(ctx->futhark);
-    ctx->futhark = NULL;
-    futhark_context_config_free(ctx->futhark_cfg);
-    ctx->futhark_cfg = NULL;
+    int err_id = 0;
+    if(futhark_context_sync((*ctx)->ctx) != 0) {
+        err_id = -1;
+    }
+    futhark_context_free((*ctx)->ctx);
+    futhark_context_config_free((*ctx)->cfg);
+    free(*ctx); *ctx = NULL;
+    return err_id;
 }
 /*------------------------------------------------------------------------------
     fmpi_futhark_sync()
 ------------------------------------------------------------------------------*/
-void fmpi_futhark_sync(struct fmpi_ctx * const ctx)
-{
-    assert(ctx != NULL);
-    futhark_context_sync(ctx->futhark);
-    fmpi_futhark_abort_on_error(ctx, "futhark_context_sync()");
-}
-/*------------------------------------------------------------------------------
-    fmpi_futhark_has_error()
-------------------------------------------------------------------------------*/
-_Bool fmpi_futhark_has_error(struct fmpi_ctx * const ctx, const char * const func_name)
+int fmpi_futhark_sync(const struct fmpi_futhark_ctx * const ctx)
 {
     assert(ctx != NULL);
-
-    char * err_str = futhark_context_get_error(ctx->futhark);
-    if(err_str != NULL) {
-        const char * func_str = func_name != NULL ? func_name : "NO_NAME";
-        fprintf(stderr, "[FUTHARK ERROR rank=%d] %s failed! %s\n", ctx->mpi->rank, func_str, err_str);
-        free(err_str); err_str = NULL;
-        return 1;
+    const int err = futhark_context_sync(ctx->ctx);
+    if(err != 0) {
+        fmpi_futhark_check_error(ctx, "futhark_context_sync");
+        return -1;
     }
     return 0;
 }
 /*------------------------------------------------------------------------------
-    fmpi_futhark_abort_on_error()
+    fmpi_futhark_check_error()
 ------------------------------------------------------------------------------*/
-void fmpi_futhark_abort_on_error(struct fmpi_ctx * ctx, const char * const func_name)
-{
+_Bool fmpi_futhark_check_error(
+    const struct fmpi_futhark_ctx * const ctx, const char * const func
+){
     assert(ctx != NULL);
-    if(fmpi_futhark_has_error(ctx, func_name)) {
-        fmpi_abort(ctx);
+    assert(func != NULL);
+    char * err_str = futhark_context_get_error(ctx->ctx);
+    if(err_str != NULL) {
+        FMPI_RAISE_FUTHARK_ERROR(ctx, "%s() failed! %s", func, err_str);
+        free(err_str); err_str = NULL;
+        return true;
     }
+    return false;
 }
-/*------------------------------------------------------------------------------
-    fmpi_new_1d()
-------------------------------------------------------------------------------*/
-#define FMPI_DEFINE_NEW_1D(T)                                 \
-FMPI_PROTO_NEW_1D(T)                                          \
-{                                                                              \
-    assert(ctx != NULL);                                                       \
-    assert(array != NULL);                                                     \
-    struct futhark_##T##_1d * xs = futhark_new_##T##_1d(ctx->futhark, array, length); \
-    fmpi_futhark_abort_on_error(ctx, CPL_STRINGIFY(futhark_new_##T##_1d())); \
-    fmpi_futhark_sync(ctx);\
-    return xs;\
-}
-/*------------------------------------------------------------------------------
-    fmpi_free_1d()
-------------------------------------------------------------------------------*/
-#define FMPI_DEFINE_FREE_1D(T)                                 \
-FMPI_PROTO_FREE_1D(T)                                          \
-{                                                                              \
-    assert(ctx != NULL);                                                       \
-    assert(array != NULL);                                                     \
-    fmpi_futhark_sync(ctx);\
-    futhark_free_##T##_1d(ctx->futhark, array);                                   \
-    fmpi_futhark_abort_on_error(ctx, CPL_STRINGIFY(futhark_free_##T##_1d())); \
+#define FMPI_FUTHARK_DEFINITION(D, T) \
+struct futhark_##T##_1d * fmpi_futhark_new_1d_##T( \
+    const struct fmpi_ctx * const ctx, const T * const array, const size_t length \
+){ \
+    assert(ctx != NULL); \
+    assert(array != NULL); \
+    struct futhark_##T##_1d * data = futhark_new_##T##_1d(ctx->fut->ctx, array, (int64_t)length); \
+    if(data == NULL) { \
+        fmpi_futhark_check_error(ctx->fut, CPL_STRINGIFY(futhark_new_##T##_1d)); \
+    } \
+    fmpi_futhark_sync(ctx->fut);\
+    return data;\
+}\
+void fmpi_futhark_free_1d_##T( \
+    const struct fmpi_ctx * const ctx, struct futhark_##T##_1d * const array \
+){ \
+    assert(ctx != NULL); \
+    assert(array != NULL); \
+    fmpi_futhark_sync(ctx->fut);\
+    const int err = futhark_free_##T##_1d(ctx->fut->ctx, array); \
+    if(err != 0) { \
+        fmpi_futhark_check_error(ctx->fut, CPL_STRINGIFY(futhark_free_##T##_1d)); \
+    } \
 }
-
-FMPI_DEFINE_FUNC(FMPI_DEFINE_NEW_1D, FMPI_FUTHARK_TYPES)
-FMPI_DEFINE_FUNC(FMPI_DEFINE_FREE_1D, FMPI_FUTHARK_TYPES)
+FMPI_DEFINE_DIM_FUNCS(FMPI_FUTHARK_DEFINITION, -, FMPI_FUTHARK_TYPES)