Skip to content
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’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extending the variables pane - Inspect #561

Merged
merged 8 commits into from
Oct 23, 2024

Conversation

dfalbel
Copy link
Contributor

@dfalbel dfalbel commented Oct 2, 2024

This a follow up for #560. See there for more details.

This PR adds support for custom inspect behavior using the ark_variable_get_child() and ark_variable_get_children() methods. It's made in a separate PR as the large diff is confusing to review. Most of it though, is a refactor to make the recursive behavior of resolve_object_from_path() more explicit.

Copy link
Contributor

@DavisVaughan DavisVaughan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I definitely don't feel like an expert on this part of the codebase, but where it seemed like new code it seems reasonable to me.

If you rebase on main hopefully the Windows failures will go away - I think we fixed the hang there.

Comment on lines +931 to +947
// something that is not a call or a symbol because it would
// have been handled in Binding::new()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you have an example of what one of these non call/symbol promise things is? Is it something we need to account for in Binding::new()?

Copy link
Contributor Author

@dfalbel dfalbel Oct 17, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't write this code, unfortunatelly this appears as lines changed due to moving for refactoring.
Also can't think of an example :(

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess parser literals could be stored in prexpr, e.g. in identity(1), in non-compiled code? (The compiler unwraps promises to constants)

crates/ark/src/variables/variable.rs Outdated Show resolved Hide resolved
Comment on lines +1017 to +1009
let child: RObject =
harp::try_catch(|| unsafe { R_do_slot(object.sexp, name) }.into())?;
return Ok(EnvironmentVariableNode::Concrete { object: child });
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's also R_has_slot() if you are worried about the slot not existing

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also didn't change that. I'm think the variables.rs file definitely deserves this kind of look, but we might want to do it in a separate PR, so we can track possible problems easier.

crates/ark/src/variables/variable.rs Outdated Show resolved Hide resolved
crates/ark/src/variables/variable.rs Outdated Show resolved Hide resolved
crates/ark/src/variables/variable.rs Outdated Show resolved Hide resolved
crates/ark/src/variables/variable.rs Outdated Show resolved Hide resolved
@dfalbel dfalbel force-pushed the feature/extend-variables branch from 96e9917 to e6e2e18 Compare October 17, 2024 19:26
@dfalbel dfalbel force-pushed the feature/extend-variables-inspect2 branch from 6938088 to b3a429f Compare October 17, 2024 20:04
@dfalbel
Copy link
Contributor Author

dfalbel commented Oct 17, 2024

I lacked git skills here , so I had to squash the changes in this PR. The history became completely meaningless due to conflicts when rebasing.

Copy link
Contributor

@lionel- lionel- left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking good. The refactored code still feels nested, it'd be nice to clean it up a bit further when we get a chance.

Comment on lines +931 to +947
// something that is not a call or a symbol because it would
// have been handled in Binding::new()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess parser literals could be stored in prexpr, e.g. in identity(1), in non-compiled code? (The compiler unwraps promises to constants)

// When building the children list of nodes that use a custom `get_children` method, the access_key is
// formatted as "custom-{index}-{length(name)}-{name}". If the access_key has this format, we call the custom `get_child_at`,
// method, if there's one available:
let result = local!({
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We avoid local! since blocks in macros cause difficulties with formatting / assistance.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also I don't see a ? so local is not needed?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 82fe440

let parsed_access_key: Vec<&str> = access_key.splitn(4, '-').collect();

if parsed_access_key.len() != 4 {
return Ok(None);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should that be logged? Same question for other failure modes.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or I guess: Should that be an Err()?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this first specific case no, because that just means that the access key does not come from a 'custom' inspect method.

The others could be logged, but in theory they could still be false positives (even though unlikely), an object could have an access key that's custom-key-a-b and get parsed until the below, so my hunch is that we don't need to do anything here.

// TODO: use ? here, but this does not return a crate::error::Error, so
// maybe use anyhow here instead ?
let row_index = path_element.parse::<isize>().unwrap();
// R6 objects may be accessed with special elements called <methods> and <private>.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you think we could move all that code to the new Ark methods?

It'd be nice to move all that complexity to the R side.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I have an initial implementation here: https://github.com/dfalbel/testVariablesPaneExtension/blob/main/R/R6.R
It's still pretty much a draft and depends a lot on rlang, but we could move it to ark and inron it out. I'd rather do it in a follow up PR though.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense!

match name.as_str() {
"<private>" => {
let env = Environment::new(object);
let enclos = Environment::new(RObject::view(env.find(".__enclos_env__")?));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you change all these view() to new() please? It's too much work to assess safety. In general view() should only be used for dispatch.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 24172d0


EnvironmentVariableNode::VectorElement {
match r_typeof(*object) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While you're in there, could you please change all *obj to the clearer obj.sexp?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 4c9b962

let dim = IntegerVector::new(Rf_getAttrib(*object, R_DimSymbol))?;
let n_row = dim.get_unchecked(0).unwrap() as isize;

// TODO: use ? here, but this does not return a crate::error::Error, so
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yep it's fine to return an Error::Anyhow variant.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in c57868a

Some(value) => {
// Make sure value is a list before using inspect_list
if !r_typeof(value.sexp) == LISTSXP {
return Err(harp::Error::Anyhow(anyhow!(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this method return an anyhow::Result instead of harp::Result?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes! 98f9996

Comment on lines 1461 to 1466
let r_names = unsafe { RObject::new(Rf_getAttrib(value.sexp, R_NamesSymbol)) };
if r_is_null(r_names.sexp) {
return vec![None; n];
}

let names = unsafe { CharacterVector::new_unchecked(r_names) };
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Simplify with RObject::attr() or RObject::names()?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in c7ae20e

let list = List::new(value.sexp)?;
let n = unsafe { list.len() };

let names = local!({
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

inline local

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 617ced8 but further simplified in c7ae20e

Base automatically changed from feature/extend-variables to main October 23, 2024 12:20
@dfalbel dfalbel force-pushed the feature/extend-variables-inspect2 branch from 24172d0 to 22490ec Compare October 23, 2024 12:38
@dfalbel dfalbel merged commit c60f560 into main Oct 23, 2024
6 checks passed
@dfalbel dfalbel deleted the feature/extend-variables-inspect2 branch October 23, 2024 12:47
@github-actions github-actions bot locked and limited conversation to collaborators Oct 23, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants