Kotlin extensions docs fix

A couple examples in the Kotlin extension functions docs show array literals that aren’t valid in Kotlin. E.g.:

FullTextIndexConfigurationFactory.create(expressions = ["name","location"])

This would be a valid array literal in Swift, but not Kotlin. Valid use would be either

FullTextIndexConfigurationFactory.create(expressions = arrayOf("name", "location"))

or without the named parameter

FullTextIndexConfigurationFactory.create("name", "location")

which wouldn’t be much different than the constructor.

I also had a question about the goal of the factory extension APIs. The docs state

these allow use of named parameters

So instead of

FullTextIndexConfiguration("name", "location")

you can do

FullTextIndexConfigurationFactory.create(expressions = arrayOf("name", "location"))

Is this the only goal, to create an API that allows explicitly using named parameters to construct objects?

The docs also allude to another potential feature of these extension functions, which is

overriding the receiver’s values with the passed parameters

But none of the examples actually show the API being used this way, always calling the API from the *Factory variables, which are null and wouldn’t have any receiver values to override.

You could also use the extension function to create a copy of an existing object, overriding some of the parameters. E.g.

val config1 = LogFileConfiguration("dir")
val config2 = config1.create(
    maxRotateCount = 10

But not all the extensions would make sense to use this way, if the object doesn’t have multiple constructor parameters or if any of their properties aren’t constructor parameters, like the IndexConfigurations.

It wouldn’t make sense to

val index1 = FullTextIndexConfiguration("name", "location")
val index2 = index1.create(expressions = arrayOf("age", "occupation"))

since index2 overrides the only parameter it could have received from index1. This could also be misleading, since the ignoreAccents value is not actually copied to index2.

I’m not sure there’s value in copying the object without modifying any parameters either.

val index1 = FullTextIndexConfiguration("name", "location")
val index2 = index1.create()

as this just results in index2 having index1’s expressions, but returning ignoreAccents to its default value of false.

If this second usage of copying parameters from one object to another isn’t a goal for an extension API, it could be prevented by making the factory an object, instead of a variable with an extension function. E.g.

object FullTextIndexConfigurationFactory {
    fun create(
        vararg expressions: String
    ) = FullTextIndexConfiguration(*expressions)

This would allow for the named parameter API usage, but prevent calling with an existing object as the receiver.

Yeah… Will forward this to the docs team.

The (modest) goal of the factories is to obviate Java Builders. You can:

  • create a new object using the factory, overriding only the properties that you want to override
  • create a new object that is like an existing object, overriding only the properties that you want to override

Ok, so it sounds like both the goals I described above are intended.

I might suggest for the classes that don’t provide constructor parameters for some of the builder functions, to extend the create() extension functions to also include these parameters, and call the builder functions with those parameters on the output. E.g.

fun FullTextIndexConfiguration?.create(
    language: String? = null,
    ignoreAccents: Boolean? = null,
    vararg expressions: String = emptyArray()
): FullTextIndexConfiguration

Right now it’s currently impossible to read the language and ignoreAccents values from a FullTextIndexConfiguration, making it impossible to accurately copy an existing object though. So this usage of the API currently may result in unexpected output.

Looks like these properties are accessible in Swift and ObjC.

The missing parameters in FullTextIndexConfiguration?.create are purely an oversight. Added.

1 Like