Object Literals struct (No named object argument)

I’ve been wondering for so long if Kotlin will have object literals struct for no named object argument.

Object Literals Struct for no named object argument:
fun someFun( arg: { name: String, email: String, password: Email } )

Why does this make sense?

  1. Some languages already have this feature, like Dart and JavaScript.

  2. Improve functional programming:
    Since a function can only have one argument, this literal object argument will be very helpful. It helps in composition; for example, if we want to make a composition like h ∘ g ∘ f(x), with too many arguments, this is hardly works. If I can describe this problem just like an Interface Coupling problem, where too many interfaces can make it hard to untangle them in the end. And in function, it’s hard to compose them up.

  3. Improve lazy evaluation with lambda:
    For example:
    ex: fun someFun( arg: () → { name: String, email: String } )
    This pattern has lots of benefits in composition. One for example; with this pattern we can add 1 layer to construct the argument, and only need one function / lambda to do it. but with multiple argument it is very ugly and too many works to do.

I tried to make a similar pattern work like this:

interface Login {
    data class X(
        var email: String = "",
        var password: String = ""
    )

    companion object {
        operator fun invoke(
            x: X.() -> Unit
        ): Result<String> {
            // x are lazily evaluated
            return X()
                .apply(x)
                .let {
                    Result.success("Success")
                }
        }
    }

}
/** Composition Example **/
val getUserInput get() = "some@email.com" to "some password"

val loginResult = Login {

    // input source
    getUserInput
        // transformation layer: input source -> payload (X)
        .let { data ->
            email = data.first
            password = data.second
        }
}

and oh im very happy using this pattern, if only it can be simpler.

Anyway i really wish we have this in kotlin, but if in case I can do this my self with KSP please enlight me how to do it (i tried but just not working yet).

At the moment you can only use anonymous classes locally within a given class/function, but they have a pretty limited usage:

val someObj = object {
	val name = "steve"
	val email = "steve@email.com"
	val password = "stevethebest"
}
someObj.name
someObj.email
someObj.password

I sometimes used them to return responses in REST endpoints, because I could easily skip declaring them as full classes this way. The downside is that you can’t declare proper return types beside Any unless objects implement some public interfaces and so on.

1 Like

that was cool, but i need the struct / contract for function argument more than the object literals.

Like I said they have a pretty limited usage :slight_smile:

Personally first I would like to have a better support for generic tuple literals (somehow releated I guess), a deep object deconstruction and a better pattern matching (even current Java is beating Kotlin in this area). Anonymous structs would also be convenient to have, but most frequently I am lacking for those features.

1 Like

I think we need to give some proposal for this? but i don’t know how… i was thinking this channel is for proposal but is saw people making proposal somewhere else.

Im trying to do this with KSP

fun someFun( arg: @ObjLiterals { name: String, email: String } )

expecting it to built into:

data class someFunArg ( val name: String .... )

but i don’t know how to use KSP… it’s been a while since im trying to do it… Now i pray for the official support lol…

I’m not an expert in this area, but I suspect this is not possible with KSP. For two reasons:

  1. We use KSP to generate new files in the project, it doesn’t allow us to manipulate the bytecode. We can generate the someFunArg class, but we can’t modify the someFun to receive it. I believe we can manipulate an existing code by writing a custom compiler plugin.
  2. Your above code is not a valid Kotlin code, so it can’t be compiled to be used by KSP. I suspect it can’t be used with a compiler plugin as well for the same reason. You would have to modify your proposed syntax to something which is a valid Kotlin code. Or maybe it is possible to write a compiler frontend plugin to hook somewhere at the AST stage (?).

Also, even if you create a function that accepts the someFunArg, how would you like to call this function? It would require to pass a class which is not visible anywhere in the source code and even IntelliJ wouldn’t help the developer too much here.

1 Like

yeah there is no way to do it without modifying the compiler… d*mn i really want that…

for current temporary strategy i use jetbrain live template to automatically create a function + data class as it’s arguments payload.

/** BEGIN $name$ Function **/
/**
 * $name$Args class - used as receiver for $name$ function
 * @property arg1 Any
 * @see $name$
 */
data class $name$Args(
    var arg1: Any = TODO()
)

/**
 * $name$ function `explain the function here`
 * @param x lambda function with $name$Args as receiver
 * @return Result<String>
 * @see $name$Args
 */
fun $name$(x: $name$Args.() -> Unit): Result<String> {
    return $name$Args()
        .apply(x)
        .let {
            TODO()
         }
}
/** END Login Function **/

well this is not a solution but until this feature available i think im using this ugly approach. at least i don’t need to make the payload name.

using lambda receiver instead of normal lambda to modify the payload using apply so i don’t have to care about the payload’s (possibly very) long name.

val LoginResult = Login {
    arg1 = "arg"
}