Kotlin / Kotlin/dataframe

Improve `inferType` documentation, KDocs, and test coverage

Open
#1,967 0 comments 0 reactions 0 assignees View on GitHub
documentation KDocs tests
Dominant language
Kotlin
Stars
1.1k
Forks
83
Avg merge
4d 12h
Merged PRs (30d)
30

Description

# Improve `inferType` documentation, KDocs, and test coverage

## Context

`inferType` is useful when a column keeps a wider type than the values currently stored in it require.

Typical cases:

- after `filter`, when a column originally typed as `Any?`, `Comparable<*>`, or `Number?` now contains only values of a more specific type;
- after manual transformations such as `convert(...).with(Infer.None)`;
- after reading or constructing loosely typed data where columns initially have broad types;
- before schema-sensitive operations that benefit from more precise column types, such as `colsOf()`, `convertTo()`, typed accessors, schema checks, or serialization.

Important distinction: `inferType` does not parse or convert values. It only refines the column type based on already stored runtime values. For example, it may refine `Any?` to `Int?` if the values are already integers, but it will not convert `"123"` to `Int`.

Current website page:
https://kotlin.github.io/dataframe/infertype.html

Current source:
`core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/inferType.kt`

Current docs source:
`docs/StardustDocs/topics/inferType.md`

Existing tests:
`core/src/test/kotlin/org/jetbrains/kotlinx/dataframe/api/inferType.kt`

## Problem

The current website page is too short and does not explain when `inferType` is useful in real DataFrame workflows.

The public API also has little or no KDoc, even though the behavior has important nuances:

- inference is based on existing runtime values;
- the result is the nearest common supertype of the values;
- inference is constrained by the current column type upper bound via `TypeSuggestion.InferWithUpperbound(type)`;
- `DataFrame.inferType()` applies to non-column-group columns at any depth;
- `inferType` is not parsing and should be distinguished from `parse` and `convert`.

The existing tests cover only a narrow subset of behavior.

## Acceptance Criteria

- The `inferType` website page explains why the operation exists and when users should consider it.
- The website clearly states that `inferType` does not parse or convert values.
- The website includes examples for whole-DataFrame inference, selected-column inference, and post-filter type refinement.
- Public non-deprecated `inferType` functions have KDocs.
- KDocs mention runtime-value-based inference, nearest common supertype behavior, and the current type upper bound.
- KDocs explain the default behavior of `DataFrame.inferType()`.
- Tests cover all non-deprecated public overloads.
- Tests cover nullable values, selected columns, whole-DataFrame inference, nested columns, and broad-to-specific type refinement.
- Tests include at least one scenario demonstrating that strings are not parsed into numbers by `inferType`.

## Website Recommendations

### 1. Add a “When to use it” section

Explain that `inferType` is useful when values have become more specific than the column type.

Suggested example:

```kotlin
val col by columnOf>("Alice", 1, 3.5)

val strings = col.filter { it is String }

strings.type() // Comparable<*>
strings.inferType().type() // String
```

### 2. Add a “What it does not do” section

Clarify that `inferType` does not parse or transform values.

Suggested example:

```kotlin
val col by columnOf("1", "2", "3")

col.inferType().type() // String?, not Int?
```

For converting strings to numbers, point users to `parse` or `convert`.

### 3. Document whole-DataFrame behavior

Explain that:

```kotlin
df.inferType()
```

infers types for non-column-group columns at any depth.

Mention that column groups themselves are not replaced by inferred value columns.

### 4. Document selected-column behavior

Show both name-based and selector-based usage:

```kotlin
df.inferType("value")
```

```kotlin
df.inferType {
colsOf()
}
```

### 5. Add a schema-sensitive workflow example

Show why type refinement is useful before operations that depend on column types:

```kotlin
val refined = df.inferType("value")

refined.select { colsOf() }
```

### 6. Link to related operations

Add a short “See also” section:

- `parse` for parsing string values into typed values
- `convert` for explicit conversion
- `convertTo()` for schema conversion

## KDoc Recommendations

Add KDocs to:

```kotlin
public fun AnyCol.inferType(): DataColumn<*>
public fun DataFrame.inferType(): DataFrame
public fun DataFrame.inferType(columns: ColumnsSelector): DataFrame
public fun DataFrame.inferType(vararg columns: String): DataFrame
```

Suggested KDoc topics:

- The operation refines column types based on already stored runtime values.
- It does not parse strings or convert values.
- The resulting type is the nearest common supertype of the current values.
- The inferred type is constrained by the current column type as an upper bound.
- `DataFrame.inferType()` applies to all non-column-group columns at any depth.
- Selected-column overloads preserve column names and positions.
- Typical use cases include post-filter narrowing, loosely typed input data, and recovery after transformations that intentionally disabled inference.

## Test Scenarios

### 1. `AnyCol.inferType()` narrows after filtering

Existing scenario can stay:

```kotlin
val col by columnOf>("Alice", 1, 3.5)
val filtered = col.filter { it is String }

filtered.inferType().type() shouldBe typeOf()
```

### 2. `DataFrame.inferType("column")` narrows a selected column

Create a DataFrame with two broad columns and verify that only the named column is refined.

### 3. `DataFrame.inferType { ... }` narrows selector-matched columns

Use a selector such as `colsOf()` or a name predicate and verify only selected columns are affected.

### 4. `DataFrame.inferType()` applies to non-column-group columns at any depth

Create a DataFrame with a nested column group containing broad typed value columns. Verify nested value columns are refined, while the column group structure is preserved.

### 5. Nullable values preserve nullability

Example expectation:

```kotlin
val col by columnOf(1, null, 2)

col.inferType().type() shouldBe typeOf()
```

### 6. Mixed values infer nearest common supertype

Example:

```kotlin
val col by columnOf(1, 2.0)

col.inferType().type()
```

Verify the expected common type according to the library’s type inference rules.

### 7. `inferType` does not parse strings

Example:

```kotlin
val col by columnOf("1", "2", "3")

col.inferType().type() shouldBe typeOf()
```

Also verify the values remain strings.

### 8. Inference respects current column type upper bound

Create a column with a declared broad-but-bounded type, then ensure inference does not produce a type outside the current upper bound.

### 9. Post-`convert(...).with(Infer.None)` refinement

Existing scenario can be kept and possibly expanded:

```kotlin
val converted = df.convert(col).with(Infer.None) {
B(it) as A
}

converted[col].type() shouldBe typeOf>()
converted.inferType(col)[col].type() shouldBe typeOf>()
```

Contributor guide

Open the contributing guide

Research direction

Start with core/src/main/kotlin/org/jetbrains/kotlinx/dataframe/api/inferType.kt and the existing test at core/src/test/kotlin/org/jetbrains/kotlinx/dataframe/api/inferType.kt, then update docs/StardustDocs/topics/inferType.md. Run the existing inferType tests before expanding coverage for the listed overloads and scenarios. Done means the website and KDocs explain runtime-based inference and its limits, and the tests cover the stated behaviors.

Written by the indexing model from the issue text.

Assessment

Tech stack
kotlin
Domain
documentation, testing-qa
Issue type
Documentation
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
72/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.