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

Define .forEach, .some, and .every methods #14

Open
parzhitsky opened this issue Apr 16, 2020 · 1 comment
Open

Define .forEach, .some, and .every methods #14

parzhitsky opened this issue Apr 16, 2020 · 1 comment
Labels
Change: minor [Issue / PR] describes a non-breaking change, such as adding a new functionality Domain: main [Issue / PR] describes change in the functionality, its optimization good first issue [Issue] can be addressed by a first-time contributor Pending: blocked [Issue / PR] cannot be addressed until another issue is resolved Priority: low [Issue / PR] could be addressed at any convenient time Type: improvement [Issue / PR] addresses lack of a functionality or an open possibility of enhancement

Comments

@parzhitsky
Copy link
Member

parzhitsky commented Apr 16, 2020

Define analogs of .forEach, .some, and .every methods of Array.prototype1.

interface Fn<Result = unknown> {
  (curr: number, count: number, memo?: Memo): Result;
}

interface XRange {
  forEach(fn: Fn, thisArg?: unknown): void;
  some(predicate: Fn<boolean>, thisArg?: unknown): boolean;
  every(predicate: Fn<boolean>, thisArg?: unknown): boolean;
}

.forEach

Fires after each of the iteration; there's no way to manually "stop" it, — it stops either automatically with the end of the range (which means it shouldn't be used with infinite ranges), or when its callback throws. Doesn't fire for non-iterated (read "empty") ranges.

.some

Short-circuited cousin of .forEach. Returns whether at least one of the calculated items fits the logic of predicate; consequently, returns false for non-iterated (read "empty") ranges. For infinite ranges either returns true (when the first fitting item is found), or hangs forever.

.every

Short-circuited cousin of .forEach. Returns whether strictly all of the calculated items fit the logic of predicate; surprisingly, returns true for non-iterated (read "empty") ranges, because of the concept of vacuous truth. For infinite ranges either returns false (when the first unfitting item is found), or hangs forever.

Considerations:

  • all three methods are provided with the most recently calculated item — curr, number of previously calculated items — count, and (optionally) the list of previously calculated items themselves — memo;

  • since count is the number of previously calculated items, it is 0-based, – i.e., by the time of the nth iteration, there are n - 1 previously calculated items;

  • memo is the array of previously calculated items in reverse order (i.e., latest to earliest), and curr is the most recent of them: curr === memo[0];

  • depending on the value of predicate.length (where predicate is a function), the value of memo might be an empty array, regardless of the actual iterations (for optimization reasons):

    declare const range: XRange;
    // in all of these scenarios, `memo` is empty,
    // since value of `callback.length` is less than 3
    range.forEach(() => {});
    range.forEach((curr) => {});
    range.forEach((curr, count) => {});
    range.forEach((curr, count, memo = []) => {});
    range.forEach((curr, count = NaN, memo) => {});
    range.forEach((curr = null, count, memo) => {});
    // these callbacks have `.length` equal to or greater than 3,
    // which allows `memo` to be calculated and provided
    range.forEach((curr, count, memo) => {});
    range.forEach((curr, count, memo, arg3) => {});
    range.forEach((curr, count, memo, arg3, arg4) => {});
    range.forEach((curr, count, memo, arg3 = DEFAULT_VALUE, arg4) => {});
    range.forEach((curr, count, memo, ...args) => {});

    Having more than three parameters however is useless here, since at most there will be only three arguments provided to callback, the rest of parameters will always remain undefined (just like in day-to-day JavaScript).


1 – For other methods (like .map of .filter etc.) require using Array.from, or perhaps consider creating separate npm package (@xrange/extras?)

@parzhitsky parzhitsky added Change: minor [Issue / PR] describes a non-breaking change, such as adding a new functionality Domain: main [Issue / PR] describes change in the functionality, its optimization Priority: low [Issue / PR] could be addressed at any convenient time Type: improvement [Issue / PR] addresses lack of a functionality or an open possibility of enhancement good first issue [Issue] can be addressed by a first-time contributor labels Apr 16, 2020
@parzhitsky parzhitsky added the Pending: blocked [Issue / PR] cannot be addressed until another issue is resolved label Jun 7, 2020
@parzhitsky
Copy link
Member Author

Blacked by parzh/xrange__core#13

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Change: minor [Issue / PR] describes a non-breaking change, such as adding a new functionality Domain: main [Issue / PR] describes change in the functionality, its optimization good first issue [Issue] can be addressed by a first-time contributor Pending: blocked [Issue / PR] cannot be addressed until another issue is resolved Priority: low [Issue / PR] could be addressed at any convenient time Type: improvement [Issue / PR] addresses lack of a functionality or an open possibility of enhancement
Projects
None yet
Development

No branches or pull requests

1 participant