diff --git a/programs/benchfn.c b/programs/benchfn.c
index 5ba0c96c29b5ed346d27273e7ea1069e8ea02b05..e2edce14e3fc167b513c8e14fa1f3ee09beb6337 100644
--- a/programs/benchfn.c
+++ b/programs/benchfn.c
@@ -48,9 +48,9 @@
 #define DEBUGOUTPUT(...) { if (DEBUG) DISPLAY(__VA_ARGS__); }
 
 /* error without displaying */
-#define RETURN_QUIET_ERROR(errorNum, retValue, ...) { \
+#define RETURN_QUIET_ERROR(retValue, ...) {           \
     DEBUGOUTPUT("%s: %i: \n", __FILE__, __LINE__);    \
-    DEBUGOUTPUT("Error %i : ", errorNum);             \
+    DEBUGOUTPUT("Error : ");                          \
     DEBUGOUTPUT(__VA_ARGS__);                         \
     DEBUGOUTPUT(" \n");                               \
     return retValue;                                  \
@@ -63,41 +63,48 @@
 
 int BMK_isSuccessful_runOutcome(BMK_runOutcome_t outcome)
 {
-    return outcome.tag == 0;
+    return outcome.error_tag_never_ever_use_directly == 0;
 }
 
 /* warning : this function will stop program execution if outcome is invalid !
  *           check outcome validity first, using BMK_isValid_runResult() */
 BMK_runTime_t BMK_extract_runTime(BMK_runOutcome_t outcome)
 {
-    assert(outcome.tag == 0);
-    return outcome.internal_never_use_directly;
+    assert(outcome.error_tag_never_ever_use_directly == 0);
+    return outcome.internal_never_ever_use_directly;
 }
 
-static BMK_runOutcome_t BMK_runOutcome_error(void)
+size_t BMK_extract_errorResult(BMK_runOutcome_t outcome)
+{
+    assert(outcome.error_tag_never_ever_use_directly != 0);
+    return outcome.error_result_never_ever_use_directly;
+}
+
+static BMK_runOutcome_t BMK_runOutcome_error(size_t errorResult)
 {
     BMK_runOutcome_t b;
     memset(&b, 0, sizeof(b));
-    b.tag = 1;
+    b.error_tag_never_ever_use_directly = 1;
+    b.error_result_never_ever_use_directly = errorResult;
     return b;
 }
 
 static BMK_runOutcome_t BMK_setValid_runTime(BMK_runTime_t runTime)
 {
     BMK_runOutcome_t outcome;
-    outcome.tag = 0;
-    outcome.internal_never_use_directly = runTime;
+    outcome.error_tag_never_ever_use_directly = 0;
+    outcome.internal_never_ever_use_directly = runTime;
     return outcome;
 }
 
 
 /* initFn will be measured once, benchFn will be measured `nbLoops` times */
 /* initFn is optional, provide NULL if none */
-/* benchFn must return a size_t value compliant with errorFn */
+/* benchFn must return a size_t value that errorFn can interpret */
 /* takes # of blocks and list of size & stuff for each. */
 /* can report result of benchFn for each block into blockResult. */
 /* blockResult is optional, provide NULL if this information is not required */
-/* note : time per loop could be zero if run time < timer resolution */
+/* note : time per loop can be reported as zero if run time < timer resolution */
 BMK_runOutcome_t BMK_benchFunction(
             BMK_benchFn_t benchFn, void* benchPayload,
             BMK_initFn_t initFn, void* initPayload,
@@ -109,10 +116,7 @@ BMK_runOutcome_t BMK_benchFunction(
             unsigned nbLoops)
 {
     size_t dstSize = 0;
-
-    if(!nbLoops) {
-        RETURN_QUIET_ERROR(2, BMK_runOutcome_error(), "nbLoops must be nonzero ");
-    }
+    nbLoops += !nbLoops;   /* minimum nbLoops is 1 */
 
     /* init */
     {   size_t i;
@@ -138,11 +142,8 @@ BMK_runOutcome_t BMK_benchFunction(
                                     dstBlockBuffers[blockNb], dstBlockCapacities[blockNb],
                                     benchPayload);
                 if (loopNb == 0) {
-                    if (errorFn != NULL)
-                    if (errorFn(res)) {
-                        BMK_runOutcome_t ro = BMK_runOutcome_error();
-                        ro.internal_never_use_directly.sumOfReturn = res;
-                        RETURN_QUIET_ERROR(2, ro,
+                    if ((errorFn != NULL) && (errorFn(res))) {
+                        RETURN_QUIET_ERROR(BMK_runOutcome_error(res),
                             "Function benchmark failed on block %u (of size %u) with error %i",
                             blockNb, (U32)srcBlockBuffers[blockNb], (int)res);
                     }
@@ -246,7 +247,7 @@ BMK_runOutcome_t BMK_benchTimedFn(
                                     cont->nbLoops);
 
         if(!BMK_isSuccessful_runOutcome(runResult)) { /* error : move out */
-            return BMK_runOutcome_error();
+            return runResult;
         }
 
         {   BMK_runTime_t const newRunTime = BMK_extract_runTime(runResult);
diff --git a/programs/benchfn.h b/programs/benchfn.h
index 3aff676d491c074e1b2b00f6c3a2fe3622212a4c..608ddfa6ee1656a106bf1c845303ca0a179fa793 100644
--- a/programs/benchfn.h
+++ b/programs/benchfn.h
@@ -26,39 +26,29 @@ extern "C" {
 #include <stddef.h>   /* size_t */
 
 
-/* ===  Variant  === */
+/* ====  Benchmark any function, iterated on a set of blocks  ==== */
 
-/* Creates a variant `typeName`, able to express "error or valid result".
- * Functions with return type `typeName`
- * must first check if result is valid, using BMK_isSuccessful_*(),
- * and only then can extract `baseType`.
- */
-#define VARIANT_ERROR_RESULT(baseType, variantName)  \
-                                             \
-typedef struct {                             \
-    baseType internal_never_use_directly;    \
-    int tag;                                 \
-} variantName
-
-
-/* ====  Benchmarking any function, iterated on a set of blocks  ==== */
+/* BMK_runTime_t: valid result type */
 
 typedef struct {
-    unsigned long long nanoSecPerRun;  /* time per iteration */
-    size_t sumOfReturn;       /* sum of return values */
+    unsigned long long nanoSecPerRun;  /* time per iteration (over all blocks) */
+    size_t sumOfReturn;         /* sum of return values */
 } BMK_runTime_t;
 
-VARIANT_ERROR_RESULT(BMK_runTime_t, BMK_runOutcome_t);  /* declares BMK_runOutcome_t */
 
-/* check first if the return structure represents an error or a valid result */
-int BMK_isSuccessful_runOutcome(BMK_runOutcome_t outcome);
-
-/* extract result from variant type.
- * note : this function will abort() program execution if result is not valid.
- *        check result validity first, by using BMK_isSuccessful_runOutcome()
- */
-BMK_runTime_t BMK_extract_runTime(BMK_runOutcome_t outcome);
+/* type expressing the outcome of a benchmark run by BMK_benchFunction().
+ * benchmark outcome might be valid or invalid.
+ * benchmark outcome can be invalid if and errorFn was provided.
+ * BMK_runOutcome_t must be considered "opaque" : never access its members directly.
+ * Instead, use its assigned methods :
+ * BMK_isSuccessful_runOutcome, BMK_extract_runTime, BMK_extract_errorResult.
+ * The structure is only described here to allow its allocation on stack. */
 
+typedef struct {
+    BMK_runTime_t internal_never_ever_use_directly;
+    size_t error_result_never_ever_use_directly;
+    int error_tag_never_ever_use_directly;
+} BMK_runOutcome_t;
 
 
 typedef size_t (*BMK_benchFn_t)(const void* src, size_t srcSize, void* dst, size_t dstCapacity, void* customPayload);
@@ -71,19 +61,20 @@ typedef unsigned (*BMK_errorFn_t)(size_t);
 
 /* benchFn - (*benchFn)(srcBuffers[i], srcSizes[i], dstBuffers[i], dstCapacities[i], benchPayload)
  *      is run nbLoops times
- * initFn - (*initFn)(initPayload) is run once per benchmark, at the beginning.
+ * initFn - (*initFn)(initPayload) is run once per run, at the beginning.
  *      This argument can be NULL, in which case nothing is run.
  * errorFn - is a function run on each return value of benchFn.
  *      Argument errorFn can be NULL, in which case nothing is run.
  *      Otherwise, it must return 0 when benchFn was successful, and >= 1 if it detects an error.
- *      Execution is stopped as soon as an error is detected, and the triggering return value is stored into sumOfReturn.
+ *      Execution is stopped as soon as an error is detected,
+ *      the triggering return value can then be retrieved with BMK_extract_errorResult().
  * blockCount - number of blocks. Size of all array parameters : srcBuffers, srcSizes, dstBuffers, dstCapacities, blockResults
  * srcBuffers - an array of buffers to be operated on by benchFn
  * srcSizes - an array of the sizes of above buffers
  * dstBuffers - an array of buffers to be written into by benchFn
  * dstCapacities - an array of the capacities of above buffers
  * blockResults - Optional: store the return value of benchFn for each block. Use NULL if this result is not requested.
- * nbLoops - defines number of times benchFn is run.
+ * nbLoops - defines number of times benchFn is run. Minimum value is 1. A 0 is interpreted as a 1.
  * @return: a variant, which express either an error, or can generate a valid BMK_runTime_t result.
  *          Use BMK_isSuccessful_runOutcome() to check if function was successful.
  *          If yes, extract the result with BMK_extract_runTime(),
@@ -105,25 +96,29 @@ BMK_runOutcome_t BMK_benchFunction(
 
 
 
-/* ====  Benchmark any function, returning intermediate results  ==== */
+/* check first if the benchmark was successful or not */
+int BMK_isSuccessful_runOutcome(BMK_runOutcome_t outcome);
 
-/* state information tracking benchmark session */
-typedef struct BMK_timedFnState_s BMK_timedFnState_t;
+/* If the benchmark was successful, extract the result.
+ * note : this function will abort() program execution if benchmark failed !
+ *        always check if benchmark was successful first !
+ */
+BMK_runTime_t BMK_extract_runTime(BMK_runOutcome_t outcome);
 
-/* BMK_createTimedFnState() and BMK_resetTimedFnState() :
- * Create/Set BMK_timedFnState_t for next benchmark session,
- * which shall last a minimum of total_ms milliseconds,
- * producing intermediate results, paced at interval of (approximately) run_ms.
+/* when benchmark failed, it means one invocation of `benchFn` failed.
+ * The failure was detected by `errorFn`, operating on return value of `benchFn`.
+ * Returns the faulty return value.
+ * note : this function will abort() program execution if benchmark did not failed.
+ *        always check if benchmark failed first !
  */
-BMK_timedFnState_t* BMK_createTimedFnState(unsigned total_ms, unsigned run_ms);
-void BMK_resetTimedFnState(BMK_timedFnState_t* timedFnState, unsigned total_ms, unsigned run_ms);
-void BMK_freeTimedFnState(BMK_timedFnState_t* state);
+size_t BMK_extract_errorResult(BMK_runOutcome_t outcome);
 
 
-/* Tells if duration of all benchmark runs has exceeded total_ms
- */
-int BMK_isCompleted_TimedFn(const BMK_timedFnState_t* timedFnState);
 
+/* ====  Benchmark any function, returning intermediate results  ==== */
+
+/* state information tracking benchmark session */
+typedef struct BMK_timedFnState_s BMK_timedFnState_t;
 
 /* BMK_benchTimedFn() :
  * Similar to BMK_benchFunction(), most arguments being identical.
@@ -143,6 +138,19 @@ BMK_runOutcome_t BMK_benchTimedFn(
                     void *const * dstBlockBuffers, const size_t* dstBlockCapacities,
                     size_t* blockResults);
 
+/* Tells if duration of all benchmark runs has exceeded total_ms
+ */
+int BMK_isCompleted_TimedFn(const BMK_timedFnState_t* timedFnState);
+
+/* BMK_createTimedFnState() and BMK_resetTimedFnState() :
+ * Create/Set BMK_timedFnState_t for next benchmark session,
+ * which shall last a minimum of total_ms milliseconds,
+ * producing intermediate results, paced at interval of (approximately) run_ms.
+ */
+BMK_timedFnState_t* BMK_createTimedFnState(unsigned total_ms, unsigned run_ms);
+void BMK_resetTimedFnState(BMK_timedFnState_t* timedFnState, unsigned total_ms, unsigned run_ms);
+void BMK_freeTimedFnState(BMK_timedFnState_t* state);
+
 
 
 #endif   /* BENCH_FN_H_23876 */