F#

Equivalencias idiomáticas entre Kotlin y F#. Kotlin se presenta como referencia en cada concepto.

Tipos paramétricos y convenciones del lenguaje

Genéricos, operadores y rangos cambian de sintaxis entre ecosistemas, pero las preguntas de diseño detrás son las mismas: qué varía, qué se comprueba y cuándo.

Equivalencia desde Kotlin

Genéricos y varianza

Cercana

En F#, anotaciones out e in en interfaces y delegados expresa la responsabilidad del fixture: Source<T> produce valores y Sink<T> los consume sin mezclar ambas responsabilidades.

Referencia Kotlin: Source<out T> es covariante y Sink<in T> es contravariante.

Mecanismo
anotaciones out e in en interfaces y delegados
Riesgo de diseño
Copiar la sintaxis de Kotlin en vez de usar anotaciones out e in en interfaces y delegados.
Recomendación
Expón el contrato del fixture y usa anotaciones out e in en interfaces y delegados solo para la garantía que realmente ofrece.

Diferencias relevantes

  • La varianza puede declararse, proyectarse en el uso o no tener una noción de subtipado equivalente.
  • La forma idiomática de F# debe conservarse aunque la sintaxis difiera de Kotlin.

Source<T> produce valores y Sink<T> los consume sin mezclar ambas responsabilidades.

type ISource<out 'T> =
    abstract Get: unit -> 'T
type ISink<in 'T> =
    abstract Put: 'T -> unit

Fuentes

Equivalencia desde Kotlin

Operadores

Cercana

En F#, miembro Contains (no existe operador de pertenencia definible por la persona usuaria) expresa la responsabilidad del fixture: Comprueba si un precio de 79.9 cae dentro de un rango válido entre 50.0 y 100.0.

Referencia Kotlin: operator fun contains permite escribir price in range para una pertenencia definida por el dominio.

Mecanismo
miembro Contains (no existe operador de pertenencia definible por la persona usuaria)
Riesgo de diseño
Copiar la sintaxis de Kotlin en vez de usar miembro Contains (no existe operador de pertenencia definible por la persona usuaria).
Recomendación
Expón el contrato del fixture y usa miembro Contains (no existe operador de pertenencia definible por la persona usuaria) solo para la garantía que realmente ofrece.

Diferencias relevantes

  • Muy pocos lenguajes permiten definir el operador de pertenencia (in) sobre un tipo propio; la mayoría exige un método con nombre como contains.
  • La forma idiomática de F# debe conservarse aunque la sintaxis difiera de Kotlin.

Comprueba si un precio de 79.9 cae dentro de un rango válido entre 50.0 y 100.0.

type PriceRange =
    { Min: float; Max: float }
    member this.Contains(price: float) = price >= this.Min && price <= this.Max

{ Min = 50.0; Max = 100.0 }.Contains(79.9)

Sin operador de invocación: una función ya se aplica yuxtaponiendo sus argumentos.

let isAboveMinimum price = price >= 10.0
isAboveMinimum 79.9

Fuentes

Equivalencia desde Kotlin

Rangos

Cercana

En F#, secuencia de rango [1 .. limit] expresa la responsabilidad del fixture: Itera los enteros desde 1 hasta limit, incluyendo limit.

Referencia Kotlin: 1..limit representa una progresión de extremos inclusivos.

Mecanismo
secuencia de rango [1 .. limit]
Riesgo de diseño
Copiar la sintaxis de Kotlin en vez de usar secuencia de rango [1 .. limit].
Recomendación
Expón el contrato del fixture y usa secuencia de rango [1 .. limit] solo para la garantía que realmente ofrece.

Diferencias relevantes

  • Un rango puede ser una colección reutilizable, un iterable perezoso o solo una forma de construir un bucle.
  • La forma idiomática de F# debe conservarse aunque la sintaxis difiera de Kotlin.

Itera los enteros desde 1 hasta limit, incluyendo limit.

[1 .. limit] |> List.iter printfn "%d"

Fuentes