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

Configuration parameter #25

Closed
Jack-Works opened this issue Apr 22, 2020 · 22 comments
Closed

Configuration parameter #25

Jack-Works opened this issue Apr 22, 2020 · 22 comments

Comments

@Jack-Works
Copy link
Member

Jack-Works commented Apr 22, 2020

In #7 (comment) @hax proposed the 3rd parameter to also accept an object to allow configuration.

let's discuss does it useful and what behavior can be configured here.

Possible usages:

  • (Implemented) step
  • custom step function (last, index) => next (Can be done with iterator helper proposal)
@hax
Copy link
Member

hax commented Apr 22, 2020

As #7

As #26

  • {inclusive}
    • false for exclusive range (use < test)
    • true for inclusive range (use <= test)

And

  • {count} (or size, or length?)
    instead of specifying step, it possible to specify iteration count so
    // definitely work for inclusive float range
    Number.range(1, 2, {count: 3, inclusive: true}) // 1, 1.5, 2
    
    // possible also work for exclusive int range
    BigInt.range(10n, 20n, {count: 3n}) // 10n, 14n, 18n

@littledan
Copy link
Member

I like the idea of the step parameter being provided with an entry in the options bag. In addition to making the API more extensible (without requiring everyone to fill in 1 for the step parameter before the fourth options bag argument, which would be ugly), it also makes code using the (rarer) step parameter more self-documenting.

@Jack-Works
Copy link
Member Author

@hax The "count" parameters can be done by:
range(start, to).take(count) // iterator helper

@littledan
Copy link
Member

Yeah, I'm pretty skeptical of the options given in #25 (comment) . useFloat is just cryptic and it's not clear when you would switch on it. I want to suggest that we use an options bag, but initially, step is the only option.

@hax
Copy link
Member

hax commented May 11, 2020

range(start, to).take(count) // iterator helper

No. What I listed have a totally different semantic.

BigInt.range(10n, 20n, {count: 3n}) // 10n, 14n, 18n
BigInt.range(10n, 20n).take(3) // 10n, 11n, 12n

Yeah, I'm pretty skeptical of the options

@littledan I just listed some possibilities in my mind (like we did for many other proposals), I don't mean any of those options are urgent to add to this proposal.

@Jack-Works
Copy link
Member Author

Although we don't have a consense now about what options should be included in this proposal, I think it seems okay to accept an options object

- Number.range(from: number, to: number, step?: number)
+ Number.range(from: number, to: number, step?: number)
+ Number.range(from: number, to: number, options?: { step?: number })

But how to expose supported options (so that polyfill authors can decide if they need to polyfill for new options)?

if ('step' in Number?.range?.options) {}
// Like this? seems strange

@littledan
Copy link
Member

littledan commented May 11, 2020

@Jack-Works Yeah, this is a general problem with options bags and feature testing... You can do a test call of Number.range with an object that has a getter to see if it's invoked. This is a bit of an ongoing problem across JS and the web platform; I don't have a great answer, see also tc39/proposal-intl-numberformat-v3#1 @sffc

@Jack-Works
Copy link
Member Author

You can do a test call of Number.range with an object that has a getter to see if it's invoked.

Oh cool trick, I didn't know that before

@hax
Copy link
Member

hax commented May 11, 2020

Personally I would write small test like:

try { Number.range(1, 3, {step:-1}) } catch {
  // feature detected!
  return
}
// do polyfill

@Jack-Works
Copy link
Member Author

@hax I don't think it is a good idea to throw for unknown options.. 🤔

@Jack-Works
Copy link
Member Author

Please check out #27 (it won't close this issue)

@sffc
Copy link

sffc commented May 12, 2020

Feature detection for specific options is not necessary unless a browser ships an incomplete implementation. Since Number.range() is new, just make sure you have good Test262 coverage and ask browsers not to ship an incomplete implementation. Feature detection just looks for the existence of a conforming Number.range symbol.

@Jack-Works
Copy link
Member Author

It is possible that we might add new options in the future after browser shiped this so feature detection might be necessary in the future

@hax
Copy link
Member

hax commented May 12, 2020

I don't think it is a good idea to throw for unknown options..

@Jack-Works
It's just an example 😆, of coz we can test for the "correct" result like:

const r = Number.range(1, 4, {step:2})
r.next()
if (r.next().value === 3)
  // feature detected!
  return
}
// do polyfill

@leobalter

This comment has been minimized.

@littledan
Copy link
Member

@leobalter I don't understand; how would a mapping function meet the use cases of the options parameter?

@leobalter
Copy link
Member

@littledan please never mind. In a second thought I don't think I want a mapping function anyway.

@Jack-Works
Copy link
Member Author

instead of an options parameters, should we consider a mapping function?

I have considered things like Number.range(0, 1000, (previous, index) => next) but the use case is not clear enough so it isn't included. But happy to hear if there is some use case for it.

@Andrew-Cottrell
Copy link

Andrew-Cottrell commented May 30, 2020

instead of an options parameters, should we consider a mapping function?

I have considered things like Number.range(0, 1000, (previous, index) => next) but the use case is not clear enough so it isn't included. But happy to hear if there is some use case for it.

I expect this sort of use case would commonly be satisfied using Iterable or Iterator utility functions; particularly a map function. My code makes frequent use of the following idiom

import * as iterables from "scheme:authority/path"
for (const square of iterables.map(Number.range(0, 5), number => number * number)) {
    console.log(square); // 0, 1, 4, 9, 16
}

And eventually we may have https://github.com/tc39/proposal-iterator-helpers

@tabatkins
Copy link

@hax:

No. What I listed have a totally different semantic.
BigInt.range(10n, 20n, {count: 3n}) // 10n, 14n, 18n

How is this different from BigInt.range(10n, 20n, {step:4n})?

@hax
Copy link
Member

hax commented Jul 8, 2020

@tabatkins The results have no difference. It just provide another way to describe the iteration. Of coz u can calculate the step from count manually but seems a little bit inconvenient (BigInt.range(start, end, {step: (end - start - 1n) / (count - 1n))

@Jack-Works
Copy link
Member Author

all options mentioned in this issue besides useFloats and count has been implemented.

About useFloats, please go #64, about count, please go #65.

I'll close this issue for housekeeping.

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

7 participants