Skip to main content

Required parameters after optional ones

REQUIRED_PARAMETER_AFTER_OPTIONAL reports required parameters of public functions and constructors declared after an optional (defaulted or vararg) parameter.

DiagnosticREQUIRED_PARAMETER_AFTER_OPTIONAL
Default severityError
Gradle propertyrequiredParameterAfterOptional
Exemption@IntentionallyRequiredParameterAfterOptional

What it reports

Every required parameter (one that doesn't have a default value) that comes after the first optional one - defaulted or vararg - in the parameter list of a public function or constructor:

@file:JvmName("Requests")
/** Sends a request to [host]. */
@JvmOverloads
public fun request(retries: Int = 3, host: String) { }

All required parameters behind the first optional one are reported, not just the first:

@file:JvmName("Configuration")
/** Configures a connection. */
@JvmOverloads
public fun configure(
timeout: Long = 0L,
host: String,
port: Int,
) { }

Rationale

A required parameter behind an optional one can't be passed positionally, which pushes callers toward named arguments for a parameter that should have been more trivial to supply. See the Kotlin library authors' guide on parameter order, naming, and usage: essential inputs first, optional inputs last.

Don't

@file:JvmName("Connections")
/** Connects to [host]. */
@JvmOverloads
public fun connect(retries: Int = 3, host: String) { }

Do

@file:JvmName("Connections")
/** Connects to [host]. */
@JvmOverloads
public fun connect(host: String, retries: Int = 3) { }

Don't

/** A server at [host]. */
public class Server
@JvmOverloads
constructor(port: Int = 80, host: String)

Do

/** A server at [host]. */
public class Server
@JvmOverloads
constructor(host: String, port: Int = 80)

Notes

  • @PublishedApi internal functions and constructors are not reported because library users cannot call them in source.
  • A vararg parameter counts as optional too: callers can omit it entirely, so a required parameter after it is still reported.
  • A required function-type or fun interface parameter in the last position is not reported: keeping it last is what makes trailing-lambda call syntax available, and the standard library itself places such parameters after defaulted ones (joinToString(separator = ..., transform)). The same required function-type parameter is still reported when it is not last, since there is no trailing-lambda syntax to preserve there.
  • Overrides are not reported: they can't declare default values, and their parameter order is fixed by the overridden declaration, which is reported instead.

Exemption

Apply @IntentionallyRequiredParameterAfterOptional to the function or constructor when the order is a deliberate, stable part of the contract, for example an old parameter list kept for source compatibility:

@file:JvmName("Connections")
/** Connects through the legacy parameter order. */
@IntentionallyRequiredParameterAfterOptional(
reason = ExemptionReason.FOR_BACKWARDS_COMPATIBILITY,
)
@IntentionallyWithoutJvmOverloads(
reason = ExemptionReason.FOR_BACKWARDS_COMPATIBILITY,
)
public fun connect(retries: Int = 3, host: String) { }

Configuration

apiWatchdog {
requiredParameterAfterOptional = WatchdogSeverity.WARNING
}

With direct compiler invocation:

-P plugin:org.jetbrains.kotlin.library.api.watchdog:diagnosticSeverity=REQUIRED_PARAMETER_AFTER_OPTIONAL:warning

See also