Skip to content

[SPARK-58043][SQL] Use explicit .apply instead of a case class companion as a function for Scala 3 compatibility#57129

Open
fangchenli wants to merge 4 commits into
apache:masterfrom
fangchenli:scala3-case-companion-function
Open

[SPARK-58043][SQL] Use explicit .apply instead of a case class companion as a function for Scala 3 compatibility#57129
fangchenli wants to merge 4 commits into
apache:masterfrom
fangchenli:scala3-case-companion-function

Conversation

@fangchenli

Copy link
Copy Markdown
Contributor

What changes were proposed in this pull request?

In Scala 2 a case class's companion object automatically extends FunctionN, so the bare companion can be passed wherever a function is expected. Scala 3 removed this (case companions no longer extend FunctionN), so these call sites fail to compile. Referencing Foo.apply, the method the synthetic FunctionN.apply forwarded to, restores the explicit form.

Why are the changes needed?

It's required for Scala 3 compatibility.

Does this PR introduce any user-facing change?

No

How was this patch tested?

Compiled with -Xsource:3

Was this patch authored or co-authored using generative AI tooling?

Generated-by: Claude Code (Claude Opus 4.8)

fangchenli and others added 2 commits July 8, 2026 10:26
…anion as a function for Scala 3 compatibility

### What changes were proposed in this pull request?
Replace bare case class companions used as function values with an explicit
`.apply` method reference across `catalyst`, `sql-core`, `hive`, and
`sql-api` (190 call sites), e.g.:
- `xs.reduceLeft(And)` -> `xs.reduceLeft(And.apply)`
- `convertUnaryExpr(expr, IsNull)` -> `convertUnaryExpr(expr, IsNull.apply)`
- `.map(sources.Not)` -> `.map(sources.Not.apply)`

Two lines are reflowed to stay within the 100-character limit.

### Why are the changes needed?
In Scala 2 a case class's companion object automatically extends `FunctionN`,
so the bare companion can be passed wherever a function is expected. Scala 3
removed this (case companions no longer extend `FunctionN`), so these call
sites fail to compile. Referencing `Foo.apply` -- the method the synthetic
`FunctionN.apply` forwarded to -- restores the explicit form. This is part of
the incremental Scala 3 readiness tracked in SPARK-54150.

### Does this PR introduce _any_ user-facing change?
No. `Foo.apply` is the exact method the synthetic `FunctionN.apply` delegated
to, so the change is behavior- and byte-identical on Scala 2.13.

### How was this patch tested?
Existing tests. The `catalyst`, `sql-core`, `hive`, and `sql-api` modules
compile under both the default build and `-Xsource:3`, `scalastyle` passes,
and no `case-companion-function` migration warnings remain in these modules.

### Was this patch authored or co-authored using generative AI tooling?
Generated-by: Claude Code (Claude Opus 4.8)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@fangchenli
fangchenli marked this pull request as ready for review July 8, 2026 17:51
fangchenli and others added 2 commits July 8, 2026 22:00
…nion-function

# Conflicts:
#	sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/V2ExpressionUtils.scala
… count for eta-expansion

The case-companion -> .apply change in QueryStartedEvent's jobTags serialization
eta-expands to a lambda, which the Scala 2.13 compiler lifts to a synthetic public
$anonfun method on the class. Reflection-based test_number_of_public_methods sees
it via getMethods(), so bump the expected count from 16 to 17.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@@ -122,15 +122,15 @@ object StructFilters {
case sources.Or(left, right) =>
zip(translate(left), translate(right)).map(Or.tupled)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

.tupled / .curried on case companions are left untouched - the modules still won't compile under real Scala 3. The same Scala 3 change (case companions no longer extend FunctionN) also breaks Foo.tupled, since tupled is a FunctionN member. These remain in bare form in the touched modules. There are also remaining .tupled uses in NaturalAndUsingJoinResolution.scala, windowExpressions.scala, and subquery.scala.

@uros-b uros-b left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@LuciferYang

LuciferYang commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

@fangchenli My question is: if we do not have an explicit plan to support Scala 3 in any major Spark release, what is the value of these changes?

@HyukjinKwon has already provided a Spark Connect client for Scala 3, and I have also developed an implementation myself. Can’t these clients solve the problem?

@HyukjinKwon

Copy link
Copy Markdown
Member

I am not against this idea but I think we should make a proper consensus, create an umbrella JIRA, and do it incrementally. We should also know that if it is possible at all to support both Scala 2 and 3 in the same source base

@fangchenli

Copy link
Copy Markdown
Contributor Author

Sorry for the response from Claude. It misunderstood my instruction.

We do have an umbrella JIRA that tracks Scala 3 support https://issues.apache.org/jira/browse/SPARK-54150.

#50474 was an attempt to do all the -Xsource:3 related changes in one PR. But it was too large to merge. Here I'm trying to break it apart to do it incrementally. I'm aware that there is no plan to support Scala 3 anytime soon. But most of those changes are pretty much mechanical and low risk.

if we do not have an explicit plan to support Scala 3 in any major Spark release, what is the value of these changes?

Those changes don't have much value if Spark won't support Scala 3 in the future. But if we do want Scala 3 support at some point, those changes are mandatory.

We should also know that if it is possible at all to support both Scala 2 and 3 in the same source base

I think we can. It might be similar to the 2.12-2.13 transition.

@LuciferYang

Copy link
Copy Markdown
Contributor

@fangchenli IIRC, https://lists.apache.org/thread/60sjx0sh525rsl1j0z4g1jsrdrs2sg96 this email is earlier discussion regarding Scala 3 on the dev mailing list.

@LuciferYang

Copy link
Copy Markdown
Contributor

I agree with @HyukjinKwon

@cloud-fan

Copy link
Copy Markdown
Contributor

Yea we need a full design of supporting both scala 2 and 3, instead of merging partial fixes without knowing what the full fix looks like.

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.

5 participants