Skip to content

Uninitialized properties without exclamation mark should cause to compile error #482

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

Closed
MaxGraey opened this issue Feb 10, 2019 · 7 comments

Comments

@MaxGraey
Copy link
Member

MaxGraey commented Feb 10, 2019

class Foo {
  notAssigned: f64; // <-- should be compile error "Property 'notAssigned' has no initializer and is not definitely assigned in the constructor."
  nonAssignedButIgnored!: f64; // has exclamation mark so valid and init as zero (default)
}
class Foo {
  notAssigned: f64; // ok! Now assigned in constructor
  nonAssignedButIgnored!: f64; // ok!
  constructor() {
     this.notAssigned = 0;
  }
}
@saulecabrera
Copy link
Contributor

saulecabrera commented Feb 25, 2020

Hey, @MaxGraey I'd like to take a stab at this one, but first I have some assumptions that I'd like to sort out.

In general, I agree that in the base case when a property is not initialized, compilation should fail, just like TS does through --strictPropertyInitialization

Now, for properties that make use of definite assignment assertions(!) do we want to initialize them with a default value as you are suggesting?

nonAssignedButIgnored!: f64; // has exclamation mark so valid and init as zero (default)

The only reason I'm asking this is that I'm thinking what would be the expectation in this case with non-basic types?

  • For basic types, I think it makes sense since they can't be null
  • For complex types, we could initialize them as well but it feels counterintuitive in terms of TypeScript compatibility.
  • Another option for complex types, we could do what Typescript does: it doesn't throw an error if the property is prefixed with ! and assumes the property will be initialized later but prior to its usage.

Thoughts?

@MaxGraey
Copy link
Member Author

MaxGraey commented Feb 25, 2020

definite assignment assertions is pretty similar to post-fix expression operator (non-null assertions) after nullable properties. It force to unsound behaviour which potentially dangerous so required runtime checks. So when we have assignment assertions for non-nullable references like that:

class Foo {
  nonAssignedButIgnored!: SomeRef
}

I guess we should do extra runtime check every time when try to access to this property like:

let foo = new Foo;
let res = foo.nonAssignedButIgnored.someMethod();

will be actually:

let res = foo.nonAssignedButIgnored !== null 
  ? foo.nonAssignedButIgnored.someMethod() 
  : unreachable();

Same approach already used for non-null assertions

@dcodeIO wdyt?

@dcodeIO
Copy link
Member

dcodeIO commented Feb 25, 2020

Definitive assignment fields feel a bit strange in a strict type context to me. My expectation so far was that we'd have field flags, like we have local flags for "possibly null", in flows eventually that would track whether a non-nullable reference typed field has been initialized either with an explicit initializer or after the constructor ran, so definitive assignment would be implicit in such scenarios. Everything else than asserting after the constructor would most likely require a runtime check as you outlined above.

@MaxGraey
Copy link
Member Author

MaxGraey commented Feb 25, 2020

Yeah, it will be great have "undefined tracking" same as nullable tracking what we already have with fallback to runtime check when impossible do this in compile time.

@saulecabrera
Copy link
Contributor

Thanks for the clarifications, all of that makes sense.

While working on this, I also found about:

class Bar {
   public run(): i32 {
      return 42;
   }
}

class Foo {
   public bar: Bar | null;

   constructor() {
      this.bar = null;
   }
}

export function run(): i32 {
   const foo = new Foo();
   return foo.bar.run();
}

When executing run I get 42 but I was expecting unreachable; I might be lacking some context, is this because we're implicitly initializing Bar?

@MaxGraey
Copy link
Member Author

When executing run I get 42 but I was expecting unreachable

Hmm this interesting. If you write with exclamation:

const foo = new Foo();
return foo.bar!.run();

you got unreachable which actually expected.
cc @dcodeIO

@dcodeIO
Copy link
Member

dcodeIO commented May 27, 2020

Closing this issue as part of 2020 vacuum because it is meanwhile tracked by a PR.

@dcodeIO dcodeIO closed this as completed May 27, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants