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

Use correct script ctx when evaluating member init #15112

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

LemonBoy
Copy link
Contributor

The initializer expression for class members is evaluated as-needed. Use the script context where the class is defined when evaluating it to avoid missing variable errors.

Closes #14011

The initializer expression for class members is evaluated as-needed. Use
the script context where the class is defined when evaluating it to
avoid missing variable errors.

Closes vim#14011
@zeertzjq zeertzjq added the vim9class Vim 9 Class Functionality label Jun 26, 2024
@LemonBoy
Copy link
Contributor Author

I think this fixes #14402 too, @errael can you confirm that's the case here?

@errael
Copy link
Contributor

errael commented Jun 26, 2024

I think this fixes #14402 too, @errael can you confirm that's the case here?

The example in #14402 does not fail with this patch; so you can add it as another issue that is fixed by this PR.

I'll play with it a little more, see if I can come up with a multi-step/nested test that also fails. Maybe I can couple my test to @lifepillar test (the tests superficially seem different).

@errael
Copy link
Contributor

errael commented Jun 27, 2024

Found another failing case which seems related.

Put the two files in the same directory.

Source obj_key.vim and it works OK with current and this PR.

t.vim

vim9script
import './obj_key.vim' as obj_key

class C1 extends obj_key.ObjKey
endclass
var o = C1.new()
echom string(o)

obj_key.vim

vim9script
echom "OBJ_KEY IMPORTED"

const DEFAULT = 'default-obj_key'

export class ObjKey
    const unique_object_id3 = DEFAULT
endclass

var o = ObjKey.new()
echom string(o)

Source t.vim with current and it fails as expected.
Looks like the original problem

OBJ_KEY IMPORTED
object of ObjKey {unique_object_id3: 'default-obj_key'}
Error detected while compiling /home/err/play/tdir2/t.vim[6]..function <SNR>45_C1.new:
line    1:
E1001: Variable not found: DEFAULT

Source t.vim with patch and it fails differently.
Looks like a similar confusion, but about export

OBJ_KEY IMPORTED
object of ObjKey {unique_object_id3: 'default-obj_key'}
Error detected while processing /home/err/play/tdir2/t.vim[6]..function <SNR>45_C1.new:
line    1:
E1049: Item not exported in script: DEFAULT

@LemonBoy
Copy link
Contributor Author

Looks like a similar confusion, but about export

That's expected, the initializer expression is taken by reference and evaluated in the new method, hence the need to make it visible from outside the script it was declared in. Note that the former error states detected while compiling while the new one detected while processing.

Is this right? I don't know. Braam modeled this behavior after Typescript (and I'm not really a fan) but have no idea of how it behaves in such situations.

@errael
Copy link
Contributor

errael commented Jun 27, 2024

Looks like a similar confusion, but about export

That's expected, the initializer expression is taken by reference and evaluated in the new method, hence the need to make it visible from outside the script it was declared in.

That sounds like an implementation issue. With that description, it could be argued that this PR as it stands is not needed.

In the OP of this PR it says

Use the script context where the class is defined

If it doesn't use the context where it is defined for execution, then why is it needed for compilation?

Note that the former error states detected while compiling while the new one detected while processing.

I thought that if it compiled, then it would run. Excluding when any is used and there's dynamic type checking involved. I looked around a little, and didn't any clarification on this. Under help constructor it says

In the second step the object variables of the parent class are initialized first.

Anyway, this behavior is confusing and shouldn't be a runtime error.

@yegappan can you offer some clarification?

Is this right? I don't know. Braam modeled this behavior after Typescript (and I'm not really a fan) but have no idea of how it behaves in such situations.

I know nothing about Typescript. But if it must fail (and I don't agree that it should), better to fail in compilation.

@LemonBoy
Copy link
Contributor Author

That sounds like an implementation issue. With that description, it could be argued that this PR as it stands is not needed.

Without this patch the compilation failed because the variable could not be found in the script context, fixing that means you can now worry about the variable being exported or not.

You can't do better than this if we wish to retain this behaviour, the new cannot be executed in the declaration context as it'll cause countless problems beside feeling wrong on many levels.

Personally speaking I don't really like this dynamic behaviour and would rather require all the initializers to be constant rvalues. We could then evaluate the initializers at compile time and use that value in the constructor, avoiding all the context-related issues.

@errael
Copy link
Contributor

errael commented Jun 27, 2024

Without this patch the compilation failed

Code that compiles should not fail at at runtime (except for type errors, probably a few other reasons)

if we wish to retain this behaviour

It's good to know that I can still be shocked an horrified by vim9script ;-)

BTW, this change is not backwards compatible (that doesn't bother me if it's a bug fix, but in this situation I'm lost).

Add this line to t.vim

var DEFAULT = 'NOT FROM obj_key.vim'

Then run t.vim, without this patch, and you get no error

OBJ_KEY IMPORTED
object of ObjKey {unique_object_id3: 'default-obj_key'}
object of C1 {unique_object_id3: 'NOT FROM obj_key.vim'}

With this patch you get an error

OBJ_KEY IMPORTED
object of ObjKey {unique_object_id3: 'default-obj_key'}
Error detected while processing /home/err/play/tdir2b/t.vim[9]..function <SNR>45_C1.new:
line    1:
E1049: Item not exported in script: DEFAULT

@dkearns Were you aware of this? Do you have any words to bring me down?

@LemonBoy
Copy link
Contributor Author

Code that compiles should not fail at at runtime

Well one could argue that the intializer expressions all must have the same privacy as the class itself. In this case the compilation would fail if the class is declared as export and the non-exported DEFAULT value is referenced as initializer.

Add this line to t.vim

The previous behaviour look quite wrong to me.

@errael
Copy link
Contributor

errael commented Jun 28, 2024

Code that compiles should not fail at at runtime

Well one could argue that the intializer expressions all must have the same privacy as the class itself. In this case the compilation would fail if the class is declared as export and the non-exported DEFAULT value is referenced as initializer.

I don't understand how it is supposed to work.

Add this line to t.vim

The previous behaviour look quite wrong to me.

What did you mean by the following?

You can't do better than this if we wish to retain this behaviour, the new cannot be executed in the
declaration context as it'll cause countless problems beside feeling wrong on many levels.

@dkearns
Copy link
Contributor

dkearns commented Jul 3, 2024

@dkearns Were you aware of this?

No, and I can't believe it's by design.

TypeScript works as expected.

Foo.ts

const DEFAULT: number = 42;

export class Foo {
    thing: number = DEFAULT;
}

Bar.ts

import { Foo } from "./Foo.ts";

class Bar extends Foo {
}

console.log(new Bar().thing); // => 42

@chrisbra
Copy link
Member

chrisbra commented Jul 6, 2024

so, can we fix it, so that is behaves like for Typescript?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
vim9class Vim 9 Class Functionality
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Variable not found when extending class with member initialized from script variable
5 participants