Skip to content

Add code evaluation API#1085

Open
jmcphers wants to merge 6 commits intomainfrom
feature/evaluate-code-api
Open

Add code evaluation API#1085
jmcphers wants to merge 6 commits intomainfrom
feature/evaluate-code-api

Conversation

@jmcphers
Copy link
Contributor

@jmcphers jmcphers commented Mar 4, 2026

This change adds an API for evaluating code to Ark.

Most of the change is actually just getting smarter about type coercion, so that named character vectors get serialized into JSON objects instead of losing their names.

Part of posit-dev/positron#7112.

@jmcphers jmcphers requested a review from DavisVaughan March 4, 2026 23:06
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.

I have a few thoughts about the new handling for character vectors. Although it is defensive regarding the presence of empty names, I'm a bit concerned that simple changes to the R representation (a name slips in) results in a completely different json representation. Also since the mapping from named vector to json map is lossy when there are duplicate names, this could lead to surprising behaviour or bugs in extension code.

But more generally, since jsonlite is the most popular serialisation package, I think it would be good to follow what it is doing, to follow the principle of least surprise.

  • Lists: Array/Object depending on presence of names (as we currently do). This suffers from type unstability for pragmatic reasons.
  • Vectors: Always as arrays, names are ignored. To get an Object, use as.list().


#[test]
#[allow(non_snake_case)]
fn test_json_named_character_vectors() {
Copy link
Contributor

Choose a reason for hiding this comment

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

Missing tests:

  • Empty character vector (empty array)
  • Character vector of size one (still an array, not a scalar)
  • Character vector with NA names (which core R methods sometimes introduce)
  • Character vector with duplicate names, should test that last one wins.

Comment on lines +254 to +256
harp::Error::TryCatchError { message, .. } => message.clone(),
harp::Error::ParseError { message, .. } => message.clone(),
harp::Error::ParseSyntaxError { message } => message.clone(),
Copy link
Contributor

Choose a reason for hiding this comment

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

I think the clones can be avoided if you match on err instead of &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.

you're right!

let names = obj.names()?;
let all_empty = names.iter().all(|name| match name {
Some(name) => name.is_empty(),
None => true,
Copy link
Contributor

Choose a reason for hiding this comment

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

NA names become None here IIUC? This would be the expected behaviour, just checking (and should also be tested).

Comment on lines +453 to +454
/// The result of evaluating the code
EvaluateCodeReply(serde_json::Value),
Copy link
Contributor

@lionel- lionel- Mar 5, 2026

Choose a reason for hiding this comment

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

By the way there's one command that I was using all the time in Emacs and that I'd like to implement in Positron. It's a version of "evaluate statement" that inserts the output of the evaluation below the statement, with #> prefix.

IIUC it's not currently possible to implement this from an extension because the evaluation needs to happen in the background (silently) but the output should still be captured and returned to the caller. It looks like that use case is not covered by posit-dev/positron#7112.

To support this case, perhaps we could consider returning a structured value with result and output fields. The output field could be opt-in by language in case the kernel can't easily support it. See #1064 for an example of how to evaluate with output and condition capture.

In any case, wrapping the return value in a struct would be more future-proof, allowing new fields to be added as needed.

@jmcphers jmcphers requested a review from lionel- March 5, 2026 19:11
@jmcphers
Copy link
Contributor Author

jmcphers commented Mar 5, 2026

@lionel- I implemented an output capture system, and also rolled back the changes to the JSON serializer. Thanks for reviewing!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants