Closed claudepache closed 7 years ago
This doesn't belong on this repository.
Thoughts?
May be useful. Is it taken from another language?
How would that interact with whitespace and thus ASI?
For this specific use case, would you not chain and call a string prototype function, which would give you a type error if it were not a string?
How would that interact with whitespace and thus ASI?
Because of ASI, LineTerminator is forbidden before a postfix “!”, so that the following code will not change semantics:
foo
!(bar)
I haven’t found other issue.
Personally I immediately thought of Ruby's dangerous methods. It shares this convention with Scheme.
For this specific use case, would you not chain and call a string prototype function, which would give you a type error if it were not a string?
Yes, job.employee?.SSN.valueOf()
will work. But what if you expect an object and don’t want to chain... augment your class with a self
accessor property, maybe?
Perhaps:
const maybeObject = job?.employee.SSN;
const importantProperty = maybeObject.something; // will throw if `maybeObject` is == null
// if it has no important properties, then why is it an object?
It might be useful in general to have some kind of "assertion" operator, despite explicit exceptions often adding clarity, but regardless I think it'd be entirely distinct from this proposal.
Perhaps:
const maybeObject = job?.employee.SSN;
Did you mean
job.employee?.SSN
?const importantProperty = maybeObject.something; // will throw if `maybeObject` is == null // if it has no important properties, then why is it an object?
It won’t work, because you don’t make the distinction between “there is no employee for the job” (which is fine) and “there is no SSN for this employee” (which is not).
It might be useful in general to have some kind of "assertion" operator, despite explicit exceptions often adding clarity, but regardless I think it'd be entirely distinct from this proposal.
However, the particular case is related, because, as the example shows, it complements optional chaining as it concerns specifically the case “== null”, with the opposite sense than “?.”
What I have specifically in mind with !
, is that the use of ?.
should not make code less safe against bugs. (It is in no way intended as a make-error-silent operator.) In details:
(A) Original code:
if (job.employee != null) {
let SSN = job.employee.SSN
// continue, with an implicit assertion that SSN is not null if employee is not null.
// If it is null, a TypeError will probably rapidly occur.
}
(B) Code using Optional Chaining, less robust:
let SSN = job.employee?.SSN
if (SSN != null) {
// continue, as above; but you have lost the implicit assertion
}
(C) Code using Optional Chaining, as robust as (A):
//explicit assertion that SSN is not null if job.employee is not null
let SSN = job.employee?.SSN!
if (SSN != null) {
// continue, as above
}
Maybe it is not necessary to resolve that issue in the scope of the present proposal. But it is good to be at least aware of it.
Maybe it is not necessary to resolve that issue in the scope of the present proposal.
Just for reference, TypeScript has a similar feature (search for “type assertion operator”).
(In reality, not the same meaning, see comment below.)
TypeScript's type assertion operator is a type hint for the compiler, not a runtime-check assertion. The two are incompatible.
In cases where the compiler can’t eliminate
null
orundefined
, you can use the type assertion operator to manually remove them.
a!
in TS anyway means that the author is 100% sure that a
is not null/undefined. I think the core intention of the proposed operator here is same.
!
has been proposed for having something to do with pattern matching/fallible patterns; we should think carefully about tradeoffs for whether we're foreclosing on those opportunities before using it here.
I’m not pursuing this idea in the scope of this proposal.
Also, once nullish-coalescing is implemented, there will be a relatively reasonable alternative:
var global = Function("return this")()
Object.defineGetter(global, 'FAIL', {
get: function() { throw new TypeError("Unexpected null") }
})
a ?? FAIL
In the future perhaps, a ?? do { throw new Error() }
@ljharb Even a ?? throw new TypeError
per Throw expressions proposal.
This:
Use case. From Jul 2017 TC39 meeting notes:
Answer:
desugars to (ignoring multiple evaluations):
Thoughts?