Skip to content

refactor(api)!: one name per meaning across the public API - #59

Merged
rducom merged 4 commits into
mainfrom
api/naming
Oct 10, 2026
Merged

rducom merged 4 commits into
mainfrom
api/naming

Conversation

@rducom

@rducom rducom commented Oct 10, 2026

Copy link
Copy Markdown
Contributor

Intent

Give the public API one vocabulary. A review of every public member found names that said something other than what the member does, words used for two things (Statistics for the data and for what a query did, Append for writing rows and for opening a writer), abbreviations, and a few members that broke rules the rest of the API keeps. The branch renames those members, writes the rules down in the public API design, and lists every rename for callers.

What it brings

  • One name per meaning. A scan's aggregates are AggregateAsync, next to CountAsync and SumAsync, and an aggregator of one's own stays an overload of the same name. What a query did is Metrics (ScanMetrics, GroupMetrics), and statistics only describe the data. A writer over an existing file comes from OpenWriterAsync, the pair of CreateWriter. A dataset lists, removes and replaces objects (ListObjectsAsync, RemoveObjectsAsync, ReplaceObjectsAsync), and deletes and updates rows.
  • Names that say what they return. CountAtKeyAsync counts the entries of the current key, and IndexOf(utf8) returns an index, -1 when no field matches.
  • One meaning per prefix. As is the same data in another form, still borrowed, so the four forms of a column read alike (AsCanonical, AsDictionary, AsRunEnd, AsConstant) and AsStorage joins them. To is an owned copy, and Get a value computed or read (GetValidLengthAsync).
  • No abbreviation (PreviousAsync, PreviousKeyAsync, SeekMode), quantities of bytes that say so (MaxDecompressedBytes, InitialReadBytes, CapacityBytes, HeldBytes), and switches that are verbs (UseStatistics, WriteStatistics, UseLeases).
  • The rules in a new "Names" section of the public API design, with a table of every rename. The query design's migration table and the queries guide point to it.

Risks and tests

  • The change breaks every caller of a renamed member. Nothing else moves: no byte on disk, no format constant, no default, no behaviour.
  • dotnet build Vorticity.slnx -c Release passes with no warning.
  • Vorticity.Tests passes in full, 7 311 tests, with 4 skipped by their own environment conditions. Vorticity.Conformance passes, 923 of 923. The MustNotCompile cases raise VX1010 and VX1011 under the new name.
  • The Zstd tests and the bench were not run, since neither the managed zstd code nor any executed path changed.
Every rename, before and now
before now
scan.AggAsync(a => e), scan.AggAsync<TResult>(a => (…)) scan.AggregateAsync(a => e), scan.AggregateAsync<TResult>(a => (…))
Statistics on a scan, a projection and an aggregation, ScanStatistics, GroupStatistics Metrics, ScanMetrics, GroupMetrics
session.AppendAsync(path) session.OpenWriterAsync(path)
dataset.ObjectsAsync(), RemoveAsync(objects), ReplaceAsync(removed, added) ListObjectsAsync(), RemoveObjectsAsync(objects), ReplaceObjectsAsync(removed, added)
cursor.KeyCountAsync(), PrevAsync(), PrevKeyAsync(), SeekOp CountAtKeyAsync(), PreviousAsync(), PreviousKeyAsync(), SeekMode
schema.TryGetField(utf8, out int index) schema.IndexOf(utf8), -1 when no field matches
column.Canonical(), column.Storage() column.AsCanonical(), column.AsStorage()
VortexFileRepair.ValidLengthAsync(path) VortexFileRepair.GetValidLengthAsync(path)
MaxDecompressedSize, MaxBatchDecompressedSize and InitialReadSize on VortexOpenOptions, VortexLimits.DefaultMaxDecompressedSize MaxDecompressedBytes, MaxBatchDecompressedBytes, InitialReadBytes, DefaultMaxDecompressedBytes
SegmentCache.Capacity, SegmentCache.Size CapacityBytes, HeldBytes
ScanOptions.Pruning, VortexWriteOptions.Statistics, CompactionSchedule.Leases UseStatistics, WriteStatistics, UseLeases
CompactionJob.Objects, GroupKeyPlan.Values, VortexDataset.ClusteringKeyPaths ObjectKeys, ValueRange, ClusteringKey
Kept as it is, on purpose
  • Counts keep their names, RowCount, ZoneCount and EntryCount next to Rows and Entries. Turning every count into one form would rename compound names such as BlocksPruned or ObjectsIn badly.
  • TimeUnit keeps its plurals (Milliseconds, Days), since a unit that counts a quantity is plural, as in TimeSpan.FromMilliseconds. CalendarUnit stays singular, since it names the period Truncate rounds down to.
  • VortexFileFormat.InitialReadSize and VortexLimits.MaxPostscriptSize are constants of the Vortex format and keep its names.
  • Sym, Expr and DType are the three abbreviations left, terms of the domain a reader meets on every page.
  • The Vortex prefix stays as it is. No rule would make it regular without renaming some thirty types.
Inside the library
  • An internal type was already named ScanMetrics: the counters a scan adds to, whose snapshot the public ScanStatistics was. It and DatasetScanMetrics became ScanCounters and DatasetScanCounters, and the internal members that hold them are named Counters, beside Metrics for the snapshot.
  • The internal read options follow the public open options into …Bytes, and the one error message that named the internal type now names VortexOpenOptions.MaxDecompressedBytes.
  • The parameter of KeyCursor<TKey>.SeekAsync is mode, after its type. The internal cursors keep op.
  • Three printed sample labels follow the new names, and the guide shows the two it quotes.
Commits
  1. The first part: the names that said something else, or used one word for two things.
  2. The second part: prefixes, abbreviations, bytes, switches and the remaining one-word-two-meanings.
  3. The rules and the table of renames in the public API design.
  4. A sample label that still printed Canonical().

The public names that said something other than what the member does, or
that used one word for two things:

- Scan<TRecord>.AggAsync(a => ...) and AggAsync<TResult>(a => (...)) are
  AggregateAsync. The name joins the terminal answers (CountAsync, SumAsync)
  without an abbreviation, and AggregateAsync<T, TAggregator, TState>, an
  aggregator of one's own, stays an overload of the same name. VX1010 and
  VX1011 look for the new name and still leave that overload alone: VX1010
  wants one type argument and a lambda that returns a tuple, VX1011 a name
  without type arguments.
- Statistics on a scan, a projection and an aggregation is Metrics, and
  ScanStatistics and GroupStatistics are ScanMetrics and GroupMetrics.
  Statistics now only names what describes the data: a file's statistics,
  zone maps, VerifyStatistics. The internal counters behind the metrics,
  ScanMetrics and DatasetScanMetrics, become ScanCounters and
  DatasetScanCounters, and the members that hold them Counters.
- VortexSession.AppendAsync(path), which returns a writer, is
  OpenWriterAsync, the pair of CreateWriter. Append now always writes rows,
  as it does on a dataset.
- VortexDataset.ObjectsAsync, RemoveAsync and ReplaceAsync are
  ListObjectsAsync, RemoveObjectsAsync and ReplaceObjectsAsync, set apart
  from DeleteAsync and UpdateAsync, which change rows.
- KeyCursor<TKey>.KeyCountAsync counted the entries of the current key, not
  the keys. It is CountAtKeyAsync.
- VortexSchema.TryGetField(utf8, out int index) returned an index. It is
  IndexOf(ReadOnlySpan<byte>), -1 when no field matches, like
  IndexOf(string).

The guide, the design documents, the samples and the tests follow, and the
public surface record is replaced.
… and switches

The members that broke a rule the rest of the API keeps:

- As is the same data in another form, still borrowed from its batch.
  Column<T>.Canonical() is AsCanonical(), so the four forms of
  ColumnEncoding read alike (AsCanonical, AsDictionary, AsRunEnd,
  AsConstant), and Storage() and Storage<TStorage>(), a view of the stored
  values, are AsStorage(). To stays an owned copy, and Get a value computed
  or read: VortexFileRepair.ValidLengthAsync is GetValidLengthAsync, like
  GetLayoutAsync.
- No abbreviation: KeyCursor<TKey>.PrevAsync and PrevKeyAsync are
  PreviousAsync and PreviousKeyAsync, and SeekOp is SeekMode, the
  parameter of SeekAsync with it.
- One word, one meaning: CompactionJob.Objects, a list of keys where
  Objects is a count everywhere else, is ObjectKeys. GroupKeyPlan.Values,
  a count where Values is the data everywhere else, is ValueRange.
  VortexDataset.ClusteringKeyPaths is ClusteringKey, as in DatasetOptions.
- A quantity of bytes ends in Bytes: VortexOpenOptions.MaxDecompressedSize,
  MaxBatchDecompressedSize and InitialReadSize, and
  VortexLimits.DefaultMaxDecompressedSize, end in Bytes, and
  SegmentCache.Capacity and Size are CapacityBytes and HeldBytes. The
  internal read options and the messages that name them follow.
- A switch is a verb: ScanOptions.Pruning is UseStatistics, the pair of
  UseIndexes, VortexWriteOptions.Statistics is WriteStatistics, and
  CompactionSchedule.Leases is UseLeases.

Counts keep their names (RowCount, ZoneCount, EntryCount next to Rows and
Entries), and TimeUnit its plurals. The guide, the design documents, the
samples, the bench and the tests follow, and the public surface record is
replaced.
The public API design gains a section on names, next to rule 6, which
decides the Async suffix: what As, To and Get return and what a method
without a prefix returns, a verb for what runs, one meaning per word
(statistics describe the data, metrics count what a query did, Create,
Open and Append, rows against objects on a dataset), names written out but
for Sym, Expr and DType, Bytes for a quantity of bytes, a verb for a
switch, and a plural for a unit that counts a quantity. A table lists
every member the two renaming commits changed, before and now, and the
query design's migration table and the guide's point to it.
@rducom
rducom merged commit 3df9976 into main Oct 10, 2026
8 checks passed
@rducom
rducom deleted the api/naming branch October 10, 2026 15:46
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

Successfully merging this pull request may close these issues.

1 participant