Skip to content

fix: return null instead of -1 from Url.effectivePort#131

Merged
OmarAlJarrah merged 4 commits into
mainfrom
a6-effectiveport-nullable
Jul 19, 2026
Merged

fix: return null instead of -1 from Url.effectivePort#131
OmarAlJarrah merged 4 commits into
mainfrom
a6-effectiveport-nullable

Conversation

@OmarAlJarrah

Copy link
Copy Markdown
Member

Summary

  • Url.effectivePort returned the java.net-style -1 sentinel for a scheme with no default port (any non-special scheme, or file), which SPEC.md's [MODEL-24] explicitly forbids: the model must never use an in-range or out-of-range magic number for "unspecified," only null.
  • Uri.effectivePort() already followed the correct sentinel-free contract (Int?, null for "no default"), and its own KDoc called out the divergence from Url. This change brings Url.effectivePort in line with it: it now returns Int? and null instead of -1.
  • A caller treating the old Int return as a real port number (a natural thing to do, since the type gave no indication otherwise) could end up trying to connect to port -1.

This is an intentional, pre-1.0 breaking API change.

Test plan

  • Added a regression test using the issue's repro (foo://host/ and file://host/, both with no default port) confirming effectivePort is null; verified it fails against the old -1-returning implementation before the fix.
  • Updated the Java interop test (PublicApiDxJavaTest) that previously pinned the Int/-1 "typing trap" to instead assert the boxed Integer/null contract, matching Uri.effectivePort().
  • ./gradlew :kuri:jvmTest :kuri:ktlintCheck :kuri:detekt :kuri:apiCheck — all green.
  • ./gradlew :kuri:jsNodeTest — green (commonMain was touched).
  • ./gradlew :kuri:macosArm64Test — green (native target compiles and passes).
  • ./gradlew apiDump run on macOS; regenerated api/jvm/kuri.api, api/android/kuri.api, and api/kuri.klib.api (confirmed the klib dump still lists the Apple targets) committed alongside the change.

Closes #114

Url.effectivePort returned the java.net-style -1 sentinel for a scheme
with no default port (any non-special scheme, or file), which SPEC.md's
[MODEL-24] explicitly forbids and which a caller could easily mistake
for a real port when connecting. Uri.effectivePort() already used the
sentinel-free Int? contract, so bring Url in line with it: effectivePort
is now Int? and returns null instead of -1. This is a breaking API
change, acceptable pre-1.0.

Closes #114
…hange

The README's Uri/Url comparison table still listed effectivePort as a
profile divergence (Url -> -1 vs Uri -> null); both now return null, so
drop the row. Url.kt's KDoc also cited MODEL-24, which types the
accessor as non-nullable and leaves the no-default case open-ended --
SCH-18 is the rule that actually mandates null for Url, matching how
Scheme.kt and Schemes.kt already cite it for the identical contract.
SPEC.md singles out 0 alongside -1 as a banned sentinel for absence,
but no test asserted that effectivePort returns a literal 0 rather
than falling back to the scheme default or null. Add one case to
each profile.
The Url.kt KDoc was already corrected (c914094) to cite SCH-18 for the
null-on-no-default behavior and MODEL-23 for the -1-sentinel ban, since
MODEL-24 types the accessor as non-nullable and leaves the no-default
case open-ended. This test comment was never updated to match.
@OmarAlJarrah
OmarAlJarrah merged commit 43b5f1d into main Jul 19, 2026
11 checks passed
@OmarAlJarrah
OmarAlJarrah deleted the a6-effectiveport-nullable branch July 19, 2026 14:11
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.

kuri: Url.effectivePort returns the -1 sentinel for the no-default-port case, which SPEC.md forbids

1 participant