denoland / rusty_v8

Rust bindings for the V8 JavaScript engine
https://crates.io/crates/v8
MIT License
3.09k stars 300 forks source link

[question] How do scopes work? #1462

Closed dev-ardi closed 2 weeks ago

dev-ardi commented 3 months ago
fn main() {
    let platform = v8::new_default_platform(0, false).make_shared();
    v8::V8::initialize_platform(platform);
    v8::V8::initialize();

    let isolate = &mut v8::Isolate::new(Default::default());
    let handle_scope = &mut v8::HandleScope::new(isolate);
    let context = v8::Context::new(handle_scope);
    let scope = &mut v8::ContextScope::new(handle_scope, context);

    {
        let scope = &mut v8::ContextScope::new(scope, context);
        let code = v8::String::new(scope, "let x = 3;").unwrap();
        let script = v8::Script::compile(scope, code, None).unwrap();
        script.run(scope).unwrap();
    }
    {
        let scope = &mut v8::ContextScope::new(scope, context);
        let code = v8::String::new(scope, "let x = 3;").unwrap();
        let script = v8::Script::compile(scope, code, None).unwrap();
        script.run(scope).unwrap();
    }
}

I'm not sure how scopes work, I would expect this to work but I get the error <unknown>:0: Uncaught SyntaxError: Identifier 'x' has already been declared.

I would expect that doing something in new scopes would be the equivalent of

{
  let x = 3;
}
{
  let x = 3;
}

which would work.

If I've misunderstood the purpose of scopes could you

  1. Clarify their purpose
  2. Explain how to do what I want to do? (not leak local variables)

After that I can submit a PR adjusting the documentation

bartlomieju commented 3 months ago

For 1. I suggest to read through this section from the V8 blog: https://v8.dev/docs/embed#handles-and-garbage-collection. TLDR: scopes are not JS scopes, but scopes for handles of V8 objects.

For 2. you wrote the solution yourself - just wrap your code in curly braces and then you will create lexical JS scopes that will not leak variables between them.

dev-ardi commented 3 months ago
let script = format!("{{{script}}}");

I temporarilly went with this but it feels really bad. Is there really not a better way?

By the way, thank you so much for pointing me to that article, I didn't know it existed. Maybe it's a good idea for it to be somewhere in the docs?

bartlomieju commented 3 months ago
let script = format!("{{{script}}}");

I temporarilly went with this but it feels really bad. Is there really not a better way?

I don't really know a native API that allows you to create lexical scopes.

By the way, thank you so much for pointing me to that article, I didn't know it existed. Maybe it's a good idea for it to be somewhere in the docs?

That sounds like a good idea. I think we could add it to docstrings for all scope types. PRs are welcome!