Repository navigation
Add DROP function (HF-384) - #1796
Tobiadefami wants to merge 36 commits into
Conversation
TAKE shipped with the English name in 10 of 16 packs while 6 carried a
translation, and VSTACK/HSTACK were English in all 16. Microsoft localizes
all three in most locales, so a user could not type the name their Excel
uses.
Names taken from Microsoft's localized "Excel functions (alphabetical)"
page, one locale at a time. Each row there links to the function's own page
using the English slug in the href while the link text is the localized
name, so the lookup is exact:
<a href="functions/take-function">WYCINEK</a>
Left as English where Microsoft itself does not translate: TAKE, VSTACK and
HSTACK in Indonesian, and VSTACK/HSTACK in Swedish.
Note that a function's own localized page is not a usable source: for
several locales its syntax block still shows the English name even though
the prose and argument names are translated (the French page shows
"=TAKE(tableau, lignes,[colonnes])" while the product uses PRENDRE).
DEV_DOCS records the lookup method and adds the governing policy: ship a
localized name only when it can be confirmed against the product, and keep
the English name otherwise, since an invented name matches nothing, reads
plausibly enough to be typed first, and fails as #NAME?.
No changelog entry: TAKE, VSTACK and HSTACK are all still in [Unreleased],
so no wrong name has been released.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This reverts commit 4459034.
Add the DROP dynamic-array function to ArrayPlugin. DROP removes rows and columns from the start (positive counts) or end (negative counts) of an array. Counts truncate toward zero, and a zero, omitted, or empty count drops nothing. Dropping every row or column returns #N/A, because HyperFormula has no #CALC! error type. Spill-size prediction uses statically known counts, so dropped rows and columns are never reserved. A whole-column or whole-row source spills from its effective size and fits only when the formula starts within the number of rows or columns dropped, matching Excel. TAKE and DROP now share the static count parser, source-range lookup, effective source sizing, and the slice that reads only the kept cells. Localized names are confirmed in Excel Online for every language pack. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
@Tobiadefami thanks for the pull request. No CLA step needed here — our records show you signed the Contributor License Agreement on 2026-07-31. That signature came from our previous signing form and has been carried over, so there is nothing for you to re-sign. |
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Deploying with
|
| Status | Name | Latest Commit | Updated (UTC) |
|---|---|---|---|
| ❌ Deployment failed View logs |
hyperformula-docs | f16a63f | Oct 15 2026, 11:57 AM |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Want higher recall? High effort reviews run extra passes and find more bugs. A team admin can switch effort levels in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 60fbf90. Configure here.
|
|
||
| if (!Number.isFinite(sourceDimension) && count.kind === 'value' && anchor > requestedDrop) { | ||
| return Number.POSITIVE_INFINITY | ||
| } |
There was a problem hiding this comment.
Unbounded spill size throws on set
Medium Severity
Predicted Infinity dimensions for whole-column or whole-row DROP and TAKE cannot be turned into a range unless the formula sits on the sheet edge. setCellContents builds that range with spanFrom, so a formula placed past the fit threshold becomes an invalid-range parse error instead of #SPILL!.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit 60fbf90. Configure here.
There was a problem hiding this comment.
Reproduced, but this isn't specific to DROP. The same formulas give #SPILL! when the sheet is built and #ERROR! ("Invalid range size.") when entered with setCellContents, and FILTER(Data!A:A, …) and SORT(Data!A:A) placed below row 1 behave the same way on develop.
DependencyGraph.exchangeOrAddFormulaVertex places the array with AbsoluteCellRange.spanFrom, which throws for an unbounded array off the sheet edge. The catch added in #1311 then turns that into a parsing error, while the build path uses spanFromOrUndef and reaches the #SPILL! check. The setCellContents result is currently pinned by #1311's tests, so changing it to #SPILL! is out of scope here. I'll raise it separately.
Performance comparison of head (f16a63f) vs base (5abbbd9) |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## develop #1796 +/- ##
===========================================
+ Coverage 97.32% 97.37% +0.04%
===========================================
Files 195 195
Lines 15739 15915 +176
Branches 3461 3567 +106
===========================================
+ Hits 15318 15497 +179
+ Misses 413 410 -3
Partials 8 8
🚀 New features to boost your workflow:
|
| const boundedDimension = Number.isFinite(sourceDimension) ? sourceDimension : effectiveDimension | ||
| return boundedDimension - Math.min(requestedDrop, boundedDimension) |
There was a problem hiding this comment.
=DROP(A:A,B1) throws out of buildFromArray when the count comes from a cell and the formula sits below row 1 on the source's own sheet:
HyperFormula.buildFromArray([[1], [2], [3], [4], [5, null, '=DROP(A:A,B1)']])
// Error: Resizing to smaller arrayThe prediction reserves 5 rows, the source's current height, and the evaluated result is 9 rows, so it cannot shrink into the reserved area. B1 empty or 1 both throw, and #1797 does not change that. TAKE(A:A,B1) throws as well once B1 exceeds the source height.
Excel Online returns #SPILL! for this formula, as it does with a literal count. It also returns #SPILL! for the cross-sheet layout in hyperformula-tests#72 (=DROP(Data!A:A,Counts!A1) at A3), where the spec expects 4 and 7. Could an unresolved count below the first row keep the unbounded dimension, so both cases return #SPILL!? A same-sheet spec would pin the crash.
There was a problem hiding this comment.
Thanks, reproduced. Fixed in ebd7363 (specs in handsontable/hyperformula-tests@f28f1f8): a count from a cell now follows the same rule as DROP(A:A,0), so your formula and the cross-sheet layout both return #SPILL!, as in Microsoft Excel Online (en-US). The one difference left is a count of 1 in row 2, where Excel spills; it's in list-of-differences.md.
The TAKE(A:A,B1) throw comes from the engine, not TAKE: it's the resize issue @sequba noted on #1722, which SORT/FILTER/UNIQUE over a whole column hit too. Tracked in #1825.
A whole-column or whole-row DROP result fits only when the formula starts within the number of rows or columns dropped. Size prediction applied that rule only to statically known counts, so a count from a cell reserved the source's current height wherever the formula was. On another sheet that spilled where Excel returns #SPILL!; on the source's own sheet the reservation made the column taller and the result threw "Resizing to smaller array". An unresolved count already counts as dropping nothing for the size bound; it now does for the placement rule too, so the result fits only in the first row or column. Documented in list-of-differences. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
I replayed the 81 layouts from hyperformula-tests#72 in Excel Online on
Would rows for these be worth adding? |
Thanks for replaying them. All three reproduce. The error fill and the cell-count reservation aren't specific to DROP, because array space is reserved before evaluation: |
Add two general rows that apply to array functions whose size is predicted before evaluation: an error result fills the whole reserved area, and a size that depends on cell values reserves the upper bound, so an occupied cell inside it gives #SPILL! where Excel spills. Add a DROP row for ISREF, which is FALSE because DROP returns values rather than a reference. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Bugbot is paused — on-demand spend limit reachedBugbot uses usage-based billing for this team and has hit its on-demand spend limit. A team admin can raise the spend limit in the Cursor dashboard, or wait for the next billing cycle to continue. |


Context
This PR adds the
DROPdynamic-array function (HF-384).DROP(array, rows, [columns])removes rows or columns from the beginning (positive counts) or the end (negative counts) of an array and returns the rest.Important
Stacked on #1722 (
TAKE). DROP reuses the count-parsing and spill-sizing helpers that TAKE introduces, so this branch is based onfeature/take-function. Until #1722 merges, this diff also shows TAKE's commits. The DROP changes are the last three commits:feat: add DROP function (HF-384),docs: link the DROP pull request in the changelog, andfix: return #SPILL! for unresolved DROP counts below the first row. Once #1722 merges, this branch will be rebased ontodevelopand only those three commits will remain.Behavior, checked against Excel:
FALSE, blank-cell, omitted, or empty count drops nothing and returns the whole array.#VALUE!, and an error in a count propagates.#N/Awith the message "Empty array not allowed.". Excel returns#CALC!, which HyperFormula does not have.Note: Microsoft's DROP page says a zero count returns
#CALC!. Excel actually returns the full array, and this implementation follows Excel.Implementation
DROPlives inArrayPlugin, next toTAKE. The two functions now share:parseLiteralCount, the static count parser (renamed fromparseTakeLiteralNumber);directSourceRange(renamed fromtakeSourceRange);effectiveSourceSize, which measures whole-column and whole-row sources;sliceSourceArray, which reads only the kept cells of an address-backed source and returns values rather than a range, so scalar coercion behaves like any other array result.TRUE()/FALSE(), parentheses, unary signs, percentages, or constant arithmetic. Dropped rows and columns are never reserved. Counts that depend on other cells reserve the source size as an upper bound, and invalid literal counts return their error instead of#SPILL!.=DROP(Data!A:A,1)fits in rows 1–2 and returns#SPILL!from row 3. A count from a cell isn't known when the spill is sized, so it follows the rule for a count of 0: the result fits only in the first row or column and returns#SPILL!below it. Excel still spills it when the formula is no lower than row count + 1; that difference is listed inlist-of-differences.md.list-of-differences.mdare included: the empty result, whole-column spills with a literal count and with a count from a cell, and array counts.TAKE's name in the same locale (for exampleINCLUIR/EXCLUIRandAL/BIRAK). Indonesian keeps the English name because Google Sheets has noDROP.How did you test your changes?
DROPtests covering every case verified in Excel, spill-size prediction, whole-column and whole-row boundaries, lazy reads, and use as an argument.TAKEtests pass unchanged after the helper refactor.DROPcases covering counts, coercion, sources, nesting, spill boundaries, and counts from a cell over whole columns.npm run compileandnpm run docs:generate-function-docspass, and lint reports no errors.Types of changes
Related issues:
TAKE).Checklist:
DROPfunction.Note
Medium Risk
New dynamic-array spill and size-prediction logic in a core plugin can affect formula evaluation and
#SPILL!handling; changes are additive but non-trivial.Overview
Adds the Excel-style
DROPdynamic-array function and wires it intoArrayPluginalongsideTAKE, with shared helpers for literal count parsing, lazy source slicing, effective whole-column/row sizing, and spill-size prediction (including anchoring rules that yield#SPILL!when an unbounded result cannot fit).DROP(array, rows, [columns])removes rows/columns from the start (positive counts) or end (negative), with zero/omitted counts leaving the array unchanged and an all-rows/columns drop returning#N/A.TAKEbehavior in the same plugin gains a dedicated zero-count error message viaErrorMessage.ZeroRowOrColumnCount.Also adds
Interpreter.isFunctionImplementedBy(used when static count parsing treatsTRUE()/FALSE()as literals), function metadata entries, changelog and compatibility-table rows forTAKE/DROP, and localizedTAKE/DROPnames across language packs.Reviewed by Cursor Bugbot for commit 60fbf90. Bugbot is set up for automated code reviews on this repo. Configure here.