`indices()` on `BaseColumn` is ambiguous for a `ColumnGroup`

オープン
#2,067 コメント 2 件 リアクション 0 件 担当者 1 名 GitHub で見る

メンテナーはふだん 1 日以内に返信

@zaleslaw がすでに取り組んでいます。

2026年9月8日 から。

評価

この issue はまだ評価されていません。

説明

bug
indices() on BaseColumn is ambiguous for a ColumnGroup

indices() exists on both BaseColumn and DataFrame:

Declaration Location
public fun AnyBaseCol.indices(): IntRange = 0 until size() core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/DataColumn.kt:325
public fun DataFrame<*>.indices(): IntRange = 0 until rowsCount() core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/indices.kt:38

ColumnGroup<T> derives from both (core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/columns/ColumnGroup.kt):

public interface ColumnGroup<out T> :
    BaseColumn<DataRow<T>>,
    DataFrame<T> {

Neither candidate is more specific for a column group, so calling indices() on one does not compile.

Reproducer

Put this file at
samples/src/test/kotlin/org/jetbrains/kotlinx/dataframe/samples/api/IndicesAmbiguityRepro.kt:

package org.jetbrains.kotlinx.dataframe.samples.api

import org.jetbrains.kotlinx.dataframe.api.indices
import org.jetbrains.kotlinx.dataframe.indices
import org.junit.Test

class IndicesAmbiguityRepro : TestBase {
    val df = peopleDf

    @Test
    fun repro() {
        df.name.indices()
    }
}

df.name is a ColumnGroup<Name> — peopleDf groups firstName and lastName into name.
Line 12 is df.name.indices(), column 17 is the indices token.

Run:

./gradlew :samples:compileTestKotlin

Output:

> Task :samples:compileTestKotlin FAILED
e: file:///.../samples/src/test/kotlin/org/jetbrains/kotlinx/dataframe/samples/api/IndicesAmbiguityRepro.kt:12:17 Overload resolution ambiguity between candidates:
fun DataFrame<*>.indices(): IntRange
fun BaseColumn<*>.indices(): IntRange

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':samples:compileTestKotlin' (registered by plugin 'org.jetbrains.kotlin.jvm').
> A failure occurred while executing org.jetbrains.kotlin.compilerRunner.btapi.BuildToolsApiCompilationWork
   > Compilation error. See log for more details
Do not check this from inside :core

The same call compiles in :core when the calling file sits in package
org.jetbrains.kotlinx.dataframe.api. There DataFrame.indices() comes from the same package
and loses to the explicit import org.jetbrains.kotlinx.dataframe.indices, so only one candidate
is considered and the ambiguity never appears. A probe in :core returns 0..2 for a
three-row column group and looks perfectly healthy. :samples is the module that reflects a
user's import set.

The property form is not affected

public val AnyCol.indices: IntRange (DataColumn.kt:317) is declared on AnyCol, which is
DataColumn<*>. ColumnGroup does not derive from DataColumn — that is deliberate, per its
own KDoc: "It derives not from DataColumn, but from BaseColumn to avoid API clashes between
DataFrame and DataColumn." So the property simply does not apply to a column group, and
there is nothing to be ambiguous about. Only the function form is broken.

Why it happens

The placement rule is written in the types themselves.

BaseColumn:

Column operations that doesn't clash by signature with DataFrame operations can be defined
for BaseColumn

DataColumn:

Column operations that have signature clash with DataFrame API (filter, take, map etc.)
are defined for DataColumn and not for BaseColumn.

indices() does clash with DataFrame.indices(), so by that rule it belongs on DataColumn,
next to filter/take/map. Putting it on BaseColumn looks like an oversight.

Suggested fix

Narrow the receiver of indices() from AnyBaseCol to AnyCol. The function and the indices
property then agree on the receiver, and a column group resolves to DataFrame.indices() — which
returns the same range anyway, because ColumnGroupImpl.size() is rowsCount()
(core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/impl/columns/ColumnGroupImpl.kt):

override fun size() = rowsCount()

Impact:

  • ValueColumn and FrameColumn are DataColumn, so they are unaffected.
  • The only in-repo use of indices on a ColumnGroup receiver is
    core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/reverse.kt:91:
    public fun <T> ColumnGroup<T>.reverse(): ColumnGroup<T> = get(indices.reversed())
    
    It uses the property. There are exactly two indices properties — AnyCol.indices and the
    internal val AnyFrame.indices (DataFrame.kt:182) — and the first does not apply to a
    column group, so this line already goes through the DataFrame side. No internal caller
    depends on the function form for column groups.
  • Narrowing the receiver of a public extension is source-breaking for any caller holding a
    BaseColumn, so this needs an apiDump and probably a deprecation cycle rather than a
    straight edit.
Current behaviour, for reference

Measured on a three-element column, and on a column group and a frame column built from a
three-row dataframe:

Call Result
col.indices 0..2
col.indices() 0..2
base.indices(), where val base: AnyBaseCol = col 0..2
group.indices() (from :core, where it compiles) 0..2
group.size() / group.rowsCount() 3 / 3
frameCol.indices / frameCol.indices() 0..2
frameCol.size() 3

IndicesTests (core/src/test/kotlin/org/jetbrains/kotlinx/dataframe/api/indices.kt, region
on a column) pins this down. The column-group case goes through a receiver explicitly typed as
AnyBaseCol, because that is the only way to call it today without hitting the ambiguity.

Tests are here: https://github.com/Kotlin/dataframe/pull/2068

主要言語
Kotlin
スター
1.1k
フォーク
87
平均マージ
2日 21時間
マージ済み PR(30日)
40

環境構築

Codespaces で開く

このプロジェクトの開発コンテナを、あなたの GitHub アカウントでブラウザ上に起動します。

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

Kotlin/dataframe のほかの issue

Kotlin/dataframe の issue をすべて見る

似ている issue

Kotlin の issue をもっと見る

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。