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

add a type to represent the undefined value #60

Closed
heycam opened this issue Oct 7, 2015 · 31 comments · Fixed by #906
Closed

add a type to represent the undefined value #60

heycam opened this issue Oct 7, 2015 · 31 comments · Fixed by #906
Labels
☕☕ difficulty:medium Hard to fix ⌛ duration:short Should be a short fix

Comments

@heycam
Copy link
Collaborator

heycam commented Oct 7, 2015

It's too awkward to deal with the undefined value by having to use any. Let's introduce a new type (undefined?) to represent that one value. Some care will be needed to make sure we handle optional arguments, distinguishability, etc. properly.

@annevk
Copy link
Member

annevk commented Oct 7, 2015

Ideally like nullability we have undefinability. This could even replace the optional argument syntax. Using [ and ] is somewhat attractive as that's already a convention of sorts, but that clashes badly with extended attributes.

(Looking at JavaScript proper perhaps nullability ought to be the special case and undefinability ought to use ?...)

@annevk
Copy link
Member

annevk commented Oct 27, 2015

We should also reconcile this with void. Perhaps get rid of the void and just have undefined. Seems better and clearer.

@annevk
Copy link
Member

annevk commented Nov 7, 2016

This comes up now and then with defining map-like constructs, where JavaScript returns undefined, but we can only do something nullable or go straight to any (e.g., CustomElementRegistry).

@jakearchibald encountered this with service workers, where something had to be a Response or undefined.

@annevk
Copy link
Member

annevk commented Nov 7, 2016

See also https://www.w3.org/Bugs/Public/show_bug.cgi?id=27549 by the way, which suggests using "optional" as syntax.

@jakearchibald
Copy link
Contributor

In our case it was a promise that resolves with Response or undefined.

caches.match(url).then(response => );

If no match is found, it resolves undefined. We've had to go with "any" to work around it, which isn't very readable.

@tabatkins
Copy link
Contributor

tabatkins commented Jan 29, 2018

I've got another case of this, and it's also about maplikes - I want to write a custom .get(), but it looks like I have to set its return type to any so that I can properly return undefined.

(I first tried to use (void or CSSStyleValue), but that's not allowed per the grammar.)

Perhaps just repurpose the existing void keyword to be a type representing the JS undefined directly, rather than being a special syntax?

@annevk
Copy link
Member

annevk commented Jan 29, 2018

"Void" might make sense for attributes and return values, but for method arguments we use "optional". For dictionary members it's "not present". I guess if we add some explanation around it's a good first step, but if we want to harmonize more with JavaScript syntax explicit undefined or dedicated syntax might be better?

@tabatkins
Copy link
Contributor

Could we take this over the finish line by settling the lingering syntax questions?

I'm not a fan of this being addressed with special syntax, like [foo]. I propose we either canonicalize void to be a type for undefined (retroactively making void foo() methods into expressing their return type directly), or just the word undefined itself (and keep the void foo() syntax form as a legacy way of spelling undefined foo()).

I don't have a strong opinion either way, it would just be useful to have this issue settled and it should be a pretty easy fix.

@saschanaz
Copy link
Member

saschanaz commented Jul 25, 2020

undefined foo() sounds a bit weird, but Promise<(object or void)> also sounds weird. 🤔 I vote for void as the former happens more frequently.

@ljharb
Copy link
Contributor

ljharb commented Jul 25, 2020

Why would undefined foo() sound any weirder than null foo() or any foo()?

@saschanaz
Copy link
Member

I mean weirder than void foo(). any looks just fine as it at least matches an existing language (TypeScript), and null foo() is rare enough if it exists.

@tabatkins
Copy link
Contributor

All right then, I'll write a PR going for void as the name for the undefined value.

@annevk
Copy link
Member

annevk commented Aug 4, 2020

I would prefer aligning on undefined as that's how JavaScript calls it and it would be annoying to have to talk about the void value in algorithm prose. It would also be more familiar for those new to IDL.

Although maybe someone knows the reason TypeScript has both void and undefined https://www.typescriptlang.org/docs/handbook/basic-types.html#void? If there's a good reason we might want to follow that.

@saschanaz
Copy link
Member

saschanaz commented Aug 4, 2020

void was initially the only choice that behaved like null | undefined. Separate null/undefined types are added as an effort for strict mode (--strictNullCheck), and void also becomes undefined in strict mode.

@annevk
Copy link
Member

annevk commented Aug 4, 2020

It seems that would argue for IDL just having undefined if we want to take inspiration from TypeScript and JavaScript?

Edit: note that another change we could make (if it doesn't make the parser ambiguous, not sure) is to allow/require omitting the return type of methods if it is undefined.

@saschanaz
Copy link
Member

saschanaz commented Aug 4, 2020

undefined foo() sounds quite like a syntactically prefixed function like async foo(), one of the reasons I find it weird.

(Another reason is just that it looks unfamiliar, though.)

@annevk
Copy link
Member

annevk commented Aug 4, 2020

Do you think we could just write foo() and leave out the type entirely in those cases?

@saschanaz
Copy link
Member

That might be a solution if it adds no ambiguity.

@TimothyGu
Copy link
Member

Do you think we could just write foo() and leave out the type entirely in those cases?

That would probably make the grammar no longer LL(1), since the parser would have to look ahead two tokens to find the (, which tells it that foo is the operation name rather than the type.

@relu91
Copy link

relu91 commented Aug 19, 2020

Sorry to bring this issue up, but I already miss the void type. As mentioned above undefined foo() sounds a little bit weird to me. I'd probably use undefined only if it has a particular meaning. For example, in a find function, I'd return undefined if I cannot find the value.

On the other hand, void is useful to state that a function does not return anything. This is also how Typescript describes the void type: https://www.typescriptlang.org/docs/handbook/basic-types.html. I'd take inspiration from there and reintroduce the void type.

@annevk
Copy link
Member

annevk commented Aug 19, 2020

For a hypothetical find() method that sometimes returns undefined the type signature would be (undefined or TODO) find(...) and not just undefined find(...). As discussed above that TypeScript has void is largely historical and its meaning (null or undefined) is not that useful.

@relu91
Copy link

relu91 commented Aug 19, 2020

As discussed above that TypeScript has void is largely historical and its meaning (null or undefined) is not that useful.

Well in my understanding, for functions it adds a particular meaning ---> no return value, which is different to return null or undefined.

@annevk
Copy link
Member

annevk commented Aug 19, 2020

function test(): void {
  return undefined;
}

is fine per https://www.typescriptlang.org/play?#code/GYVwdgxgLglg9mABFApgZygCgJQC5EBucMAJogN4BQiiATilCLUuCSsDGCiQNyUC+QA. And it would be somewhat weird if it was not as a function lacking a return statement and one returning undefined are identical in JavaScript.

If you use IDL for other languages you can continue to assume that a function whose return type is exclusively undefined returns nothing, just like it returns "nothing" in JavaScript.

@zolkis
Copy link

zolkis commented Aug 19, 2020

There are theoretical points for void and practical points for undefined, also seen in TypeScript (makes a strong point for void, but relaxes it in practive - we should not follow that if not needed).

However, a good explainer is due (a digest of this issue discussion might serve as one).

I would aesthetically prefer to say void for functions that actually don't return anything, in order to state there is no return value. A function that does not return a value is analogous to a property not being present, rather than one being present but having the undefined value.

Between returning (undefined or TYPE) and (void or TYPE) I strongly prefer the former.

Applying Occam's tool indeed suggests getting rid of void, but I just can't get over the new signatures like
Promise<undefined> instead of Promise<void>
and
undefined foo() instead of void foo():
it does not seem to be an exact formulation.

@relu91
Copy link

relu91 commented Aug 19, 2020

This is not fine however:

function test(): undefined {
  console.log("hey")
}

https://www.typescriptlang.org/play?#code/GYVwdgxgLglg9mABFApgZygCgJQC5HgAmKwMYKhiA3gFCKIQJpwA2KAdC3AOaYBEACxQBPPthoBfIA

@domenic
Copy link
Member

domenic commented Aug 19, 2020

It's possible that the needs of TypeScript and Web IDL diverge, and that's OK. Web IDL intends to model JavaScript, where functions that don't return anything, return undefined.

There is no distinction in JavaScript between functions that "actually don't return anything" vs. "returning undefined", and so we won't make such a distinction in Web IDL.

@saschanaz
Copy link
Member

saschanaz commented Aug 19, 2020

Filed microsoft/TypeScript#40133 as that looks like a bug to me. (Oops, a duplicate of microsoft/TypeScript#36288)

@ExE-Boss
Copy link
Contributor

TypeScript uses void in ways other than undefined, e.g.: this: void in function definitions or trailing void parameters being treated as optional.

saschanaz added a commit to saschanaz/css-houdini-drafts that referenced this issue Mar 3, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
☕☕ difficulty:medium Hard to fix ⌛ duration:short Should be a short fix
Development

Successfully merging a pull request may close this issue.