New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add isValid to nix::Value #10555
Add isValid to nix::Value #10555
Conversation
ec0d8f6
to
0be906b
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a valid problem, but "unset" could be part of the language, whereas this is decidedly about the implementation of the evaluator+bindings.
We have some non-null checks for Value *
; perhaps we should also check against uninitialized values in those call sites, and have a helper for that? We could name the helpers after the in
and out
documented in the parameters.
We might even check that out
is uninitialized. We don't want callers to create mutable variables; that would lead to horribly unpredictable outcomes.
src/libexpr/value.hh
Outdated
@@ -23,6 +23,7 @@ class BindingsBuilder; | |||
|
|||
|
|||
typedef enum { | |||
tUnset, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
tUnset, | |
tInvalid = 0, |
This suggests being part of the implementation more so than the language itself.
For instance, an attribute can be unset, but in that case we return NULL
and set NIX_ERR_KEY
.
(Also make the 0
explicit)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually this might be better
tUnset, | |
tUninitialized, |
src/libexpr/value.hh
Outdated
@@ -294,6 +296,11 @@ public: | |||
internalType = newType; | |||
} | |||
|
|||
inline bool isInitialized() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
inline bool isInitialized() | |
/** A value becomes valid when it is initialized. We don't use this in the evaluator; only in the bindings, where the slight extra cost is warranted because of inexperienced callers. */ | |
inline bool isValid() |
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Close to ready for merge, but also have suggestions to make it a bit more ergonomic.
src/libexpr-c/nix_api_value.cc
Outdated
@@ -20,7 +20,7 @@ | |||
# include "gc_cpp.h" | |||
#endif | |||
|
|||
// Helper function to throw an exception if value is null | |||
// Helper function to throw an exception if value is null or in an invalid state |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This wasn't actually changed.
// Helper function to throw an exception if value is null or in an invalid state | |
// Helper function to throw an exception if value is null |
tests/unit/libexpr/nix_api_value.cc
Outdated
|
||
TEST_F(nix_api_expr_test, nix_value_set_get_float) | ||
{ | ||
float myDouble = 1.0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unrelated, but this freaked me out for a sec. It doesn't seem to serve a purpose.
float myDouble = 1.0; | |
double myDouble = 1.0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oops, good catch, addressed it here: f7da544
ASSERT_DEATH(nix_get_list_byidx(ctx, value, state, 0), ""); | ||
ASSERT_DEATH(nix_get_list_size(ctx, value), ""); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
馃帀
Was considering to get rid of these, because ASSERT_DEATH
is slow.
@@ -33,5 +35,14 @@ protected: | |||
std::string msg(p, n); | |||
FAIL() << "nix_err_code(ctx) != NIX_OK, message: " << msg; | |||
} | |||
|
|||
inline void assert_ctx_err() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not immediately necessary, but it would be good to check the kind of error, and return the message (for when that's relevant to check).
inline void assert_ctx_err() | |
inline std::string assert_ctx_err(nix_err expected_err) |
or const char *
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed, but I'd prefer to open a new PR, this one is getting big enough.
src/libexpr-c/nix_api_value.cc
Outdated
auto & v = check_value_not_null(value); | ||
check_value_initialized(v); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
check_value_initialized
is only used after check_value_not_null
, which suggests that we should perhaps have a helper function that does both?
We can then also rephrase it in higher level terms:
check_value_in
: check_value_not_null
+ check_value_initialized
check_value_out
: check_value_not_null
+ check_value_uninitialized
The only other cases I can think of now, where we might want to use check_value_initialized
separately is
- nullable parameters. For those we could have
check_value_in_or_null
. - checking multiple values in a buffer, e.g. list or attrset builder. I'm not entirely sure we should do that, because it makes constructing cyclic structures difficult.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Makes sense, I added check_value_in
and check_value_out
helpers. I'm not happy about having separate versions for const
and non-const
data, but I can't think of a good solution. link to the code
nullable parameters. For those we could have
check_value_in_or_null
.
Good point. However, I don't believe we currently have any functions that accept nullable values. If necessary, we can add a helper function for that in the future.
checking multiple values in a buffer, e.g. list or attrset builder. I'm not entirely sure we should do that, because it makes constructing cyclic structures difficult.
In addition, the order of calling nix_init_*
and nix_[list,builder]_builder_insert
shouldn't matter. I've updated these functions to only check for a null value.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@roberth Kindly pinging you, since I think you might have missed the latest changes. (If not, no worries, just wanted to make sure you're aware, and take your time to review it)
Add a method to check if a value has been initialized. This helps avoid segfaults when calling `type()`. Useful in the context of the new C API. Closes NixOS#10524
d770b4b
to
6acf02b
Compare
Motivation
Add a method to check if a value has been initialized. This helps avoid segfaults when calling
type()
.Useful in the context of the new C API.
Context
Closes #10524
Priorities and Process
Add 馃憤 to pull requests you find important.
The Nix maintainer team uses a GitHub project board to schedule and track reviews.