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

Is empty tuple / record falsy? #380

Open
tiansh opened this issue Jul 10, 2023 · 7 comments
Open

Is empty tuple / record falsy? #380

tiansh opened this issue Jul 10, 2023 · 7 comments

Comments

@tiansh
Copy link

tiansh commented Jul 10, 2023

I have not find any specification about the truthy / falsy about the tulpe or records. I had tested the playground and it currently report !!#[] and !!#{} as true. However, I would expect it as falsy just like what assert(!!"" === false) do. Is this something not decided yet or could anyone point me a link to the previous discuses?

@ljharb
Copy link
Member

ljharb commented Jul 10, 2023

I’d expect it to be truthy, since every container in the language is truthy when empty. Being a primitive would mean it could be falsy, of course, but I’m not sure that’d be useful.

@gregmartyn
Copy link

The non-empty equality tests (#{some: "thing"} === #{some: "thing"} while {some: "thing"} !== {some: "thing"}) are already one of the big differences with the other containers, so different semantics for empty wouldn't be particularly surprising. In fact, having empty be falsy would be more in line with the other primitives. (like "" as mentioned above)

@acutmore
Copy link
Collaborator

I have not find any specification about the truthy / falsy about the tulpe or records.

The specification can be found in the ToBoolean abstract operation.

https://tc39.es/proposal-record-tuple/#sec-toboolean

@tiansh
Copy link
Author

tiansh commented Jul 11, 2023

I would expect is as falsy:

  1. Strings can be considered as containers of characters, and empty strings are falsy already. So I would expect other primitive containers such as tuples and records to have the same behavior, which would be less surprising to me.
  2. Some languages like Python treat empty containers as falsy. This makes sense to programmers. Testing if a container is empty is a common operation during programming. However, testing if it is a tuple vs null could be less useful. Also, since we already have the ?? operator introduced into JavaScript, when users want nullish fallback, they can use ?? instead of ||. So the falsy behavior won’t make such scenarios more complex.
  3. The boolean conversion behavior does not need to align with Object or Array. As the equality comparison has already made a very different behavior here. Programmers are trained that such types have different behaviors compared to Object.
  4. You may fell that making #{} and #[] falsy but keeping [] and {} are thuthy confusion, but same thing already happened on other types, for example, "", 0, false are falsy, but Object(""), Object(0), Object(false) are truthy already.

@LongTengDao
Copy link

If empty is falsy, what value does this additional difference generate?

I can't image when any code I seen try to check specially whether there is keys in an options object. And tuple's length should be easy to check.

Expanding falsy value list should be very careful and necessary, as many type guard of existing libraries may relax their vigilance against false values.

BigInt 0n can't have ownProperty, so it's reluctantly ok. I think there will be risk, unless there is sufficient reason.

At least, I think only empty tuple could be falsy, but not record.

But again, I think there will be many user pass tuple and record to lib api which only know array and object instead of them. Think about below:

export function lib_api_2 (allows) {
    if ( !allows ) { allows = [ 'defaultAllow' ]; }
}

export function lib_api_1 (options) {
    if ( !options ) { options = { defaultFeature: true }; }
}

@js-choi
Copy link

js-choi commented Dec 2, 2023

"" as a falsy “container” is a precedent, but [] as a truthy container is also a precedent.
I think that congruency between #[] and [] is more important than #[] being congruent with "".

This proposal has already established the following design goal: to allow generic functions to generically take arrays or tuples (see “Why are Record & Tuple not based on .get()/.set() methods like Immutable.js?”). As @LongTengDao’s example demonstrates, making !!#[] be different from !![] would undermine this genericness goal.

If you want to allow generic functions that would treat arrays and tuples equivalently, and if [] is truthy, then #[] should also be truthy.
In contrast, (almost?) no one is going to write generic functions that treat strings and tuples equivalently.

@tiansh
Copy link
Author

tiansh commented Dec 5, 2023

If empty is falsy, what value does this additional difference generate?

I can't image when any code I seen try to check specially whether there is keys in an options object. And tuple's length should be easy to check.

Expanding falsy value list should be very careful and necessary, as many type guard of existing libraries may relax their vigilance against false values.

BigInt 0n can't have ownProperty, so it's reluctantly ok. I think there will be risk, unless there is sufficient reason.

At least, I think only empty tuple could be falsy, but not record.

But again, I think there will be many user pass tuple and record to lib api which only know array and object instead of them. Think about below:

export function lib_api_2 (allows) {
    if ( !allows ) { allows = [ 'defaultAllow' ]; }
}

export function lib_api_1 (options) {
    if ( !options ) { options = { defaultFeature: true }; }
}

For old codes that not designed to work with immutable object (aka, records), any behavior you have chosen would definitely not working. As you cannot assign allows.defaultFeature any way without getting an error if allows is immutable. And since the record is introduced as a new feature, it wont break any exists codes, but only new codes that misused the interface by passing record while it required a object.

If you try to feed an API which require number with Object(0), you may also mass up many currently exists codes.

And for newer codes, you can simply use default parameter or ?? operator to avoid any confusion.

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

No branches or pull requests

6 participants