Skip to content

[Android] Support Collections DSL Part 2 - Mutable Collection Factory Functions #966

@l2hyunwoo

Description

@l2hyunwoo

Introduction

Following the previous proposal for buildReadableMap and buildReadableArray DSLs (which align with Kotlin’s builder pattern), I would like to propose adding factory functions for creating WritableMap and WritableArray.

In the Kotlin standard library, mutable collections are typically created using factory functions like mutableMapOf(...) or mutableListOf(...). Introducing writableMapOf(...) and writableArrayOf(...) to React Native’s Android codebase would provide a consistent, idiomatic way to initialize mutable native maps and arrays.

Details

Currently, initializing a WritableMap with values requires imperative calls:

val params = Arguments.createMap().apply {
    putString("name", "hyunwoo lee")
    putInt("age", 28)
    putBoolean("loveRN", true)
}

With the proposed factory functions, developers can initialize mutable maps and arrays using the familiar vararg syntax found in Kotlin’s standard library:

val params = writableMapOf(
    "name" to "hyunwoo lee",
    "age" to 28,
    "loveRN" to true
)

val fruits = writableArrayOf("apple", "banana", "cherry")

This significantly reduces boilerplate when passing arguments to JS, emitting events, or resolving Promises with simple data structures.

Proposed API

The API mirrors the standard library's mutableMapOf and mutableListOf:

/**
 * Creates a WritableMap with the given key-value pairs.
 */
fun writableMapOf(vararg pairs: Pair<String, Any?>): WritableMap

/**
 * Creates a WritableArray with the given elements.
 */
fun writableArrayOf(vararg elements: Any?): WritableArray

Usage Examples:

// Sending an event with data
sendEvent("onPress", writableMapOf(
    "x" to 100,
    "y" to 200,
    "metadata" to writableMapOf( // Nested creation
        "timestamp" to System.currentTimeMillis()
    )
))

// Resolving a promise with a mixed array
promise.resolve(writableArrayOf(1, "success", true))

Discussion points

Type Safety vs. Developer Experience (...Of factory methods)

Unlike the buildReadableMap DSL, which uses function overloading to enforce type safety at compile-time, the proposed writableMapOf factory relies on vararg pairs: Pair<String, Any?>.

This introduces a trade-off:

  • Pros: It provides the familiar Kotlin mapOf syntax, making code significantly concise for flat structures.

  • Cons: It relies on runtime type checking. Passing an unsupported type (e.g., Date or a custom class) will not be caught by the compiler and will result in a runtime exception (or explicit error) inside the factory function.

Is this trade-off acceptable for the sake of providing idiomatic Kotlin Syntax? Or should we strictly stick to the Type-Safe Builder DSL (buildWritableMap) to prevent runtime crashes?
In My opinion: Both should be provided—Builders for complex/safe logic, Factories for simple/quick initialization.

Please share your thoughts! Feedback on API shape, scope, or anything else is very welcome.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions