From c121c6564052381c8067ce5c31d5418e968f69e5 Mon Sep 17 00:00:00 2001 From: Robert Hensing Date: Sat, 20 Sep 2025 00:47:00 +0200 Subject: [PATCH] C API: Clarify valid use of bindings ordering --- src/libexpr-c/nix_api_value.h | 42 ++++++++++++++++++++++++++++++----- 1 file changed, 37 insertions(+), 5 deletions(-) diff --git a/src/libexpr-c/nix_api_value.h b/src/libexpr-c/nix_api_value.h index 38fede62b..835eaec6e 100644 --- a/src/libexpr-c/nix_api_value.h +++ b/src/libexpr-c/nix_api_value.h @@ -315,10 +315,20 @@ nix_get_attr_byname_lazy(nix_c_context * context, const nix_value * value, EvalS */ bool nix_has_attr_byname(nix_c_context * context, const nix_value * value, EvalState * state, const char * name); -/** @brief Get an attribute by index in the sorted bindings +/** @brief Get an attribute by index * * Also gives you the name. * + * Attributes are returned in an unspecified order which is NOT suitable for + * reproducible operations. In Nix's domain, reproducibility is paramount. The caller + * is responsible for sorting the attributes or storing them in an ordered map to + * ensure deterministic behavior in your application. + * + * @note When Nix does sort attributes, which it does for virtually all intermediate + * operations and outputs, it uses byte-wise lexicographic order (equivalent to + * lexicographic order by Unicode scalar value for valid UTF-8). We recommend + * applying this same ordering for consistency. + * * Use nix_gc_decref when you're done with the pointer * @param[out] context Optional, stores error information * @param[in] value Nix value to inspect @@ -330,10 +340,22 @@ bool nix_has_attr_byname(nix_c_context * context, const nix_value * value, EvalS nix_value * nix_get_attr_byidx(nix_c_context * context, nix_value * value, EvalState * state, unsigned int i, const char ** name); -/** @brief Get an attribute by index in the sorted bindings, without forcing evaluation of the attribute's value +/** @brief Get an attribute by index, without forcing evaluation of the attribute's value * - * Also gives you the name. Returns the attribute value without forcing its evaluation, allowing access to lazy values. - * The attribute set value itself must already be evaluated. + * Also gives you the name. + * + * Returns the attribute value without forcing its evaluation, allowing access to lazy values. + * The attribute set value itself must already have been evaluated. + * + * Attributes are returned in an unspecified order which is NOT suitable for + * reproducible operations. In Nix's domain, reproducibility is paramount. The caller + * is responsible for sorting the attributes or storing them in an ordered map to + * ensure deterministic behavior in your application. + * + * @note When Nix does sort attributes, which it does for virtually all intermediate + * operations and outputs, it uses byte-wise lexicographic order (equivalent to + * lexicographic order by Unicode scalar value for valid UTF-8). We recommend + * applying this same ordering for consistency. * * Use nix_gc_decref when you're done with the pointer * @param[out] context Optional, stores error information @@ -346,10 +368,20 @@ nix_get_attr_byidx(nix_c_context * context, nix_value * value, EvalState * state nix_value * nix_get_attr_byidx_lazy( nix_c_context * context, nix_value * value, EvalState * state, unsigned int i, const char ** name); -/** @brief Get an attribute name by index in the sorted bindings +/** @brief Get an attribute name by index * * Returns the attribute name without forcing evaluation of the attribute's value. * + * Attributes are returned in an unspecified order which is NOT suitable for + * reproducible operations. In Nix's domain, reproducibility is paramount. The caller + * is responsible for sorting the attributes or storing them in an ordered map to + * ensure deterministic behavior in your application. + * + * @note When Nix does sort attributes, which it does for virtually all intermediate + * operations and outputs, it uses byte-wise lexicographic order (equivalent to + * lexicographic order by Unicode scalar value for valid UTF-8). We recommend + * applying this same ordering for consistency. + * * Owned by the nix EvalState * @param[out] context Optional, stores error information * @param[in] value Nix value to inspect