Short form for anonymous objects

Can we support a short form declaration for anonymous objects:

val person = object {
    val name = "John"
    val age = 28
}

I would like to write like this:
val person = (name = "John", age = 28)

If the right side is a property, it should be omitted:
val person = (otherPerson.name, otherPerson.age)

I need that because I’m writing a library that supports querying sqlite on Android. The current declaration makes my codes not pretty:

 newContext {
                from(Songs join Libraries on { x, y -> x.libraryId eq y.id })
                        .where { (_, library) -> library.continuous eq true }
                        .select { (song, library) ->
                            object {
                                val title = song.title
                                val libraryName = library.name
                            }
                        }
                        .collect {
                            object {
                                val title = it.get { title }
                                val libraryName = it.get { libraryName }
                            }
                        }.forEach {
                            println("${it.title} : ${it.libraryName}")
                        }
            }

It’s better if we allow to write like that:

    newContext {
        from(Songs join Libraries on { x, y -> x.libraryId eq y.id })
                .where { (_, library) -> library.continuous eq true }
                .select { (song, library) -> (song.title, library.name) }
                .collect {
                    (
                            title = it.get { title } ,
                            libraryName = it.get { libraryName }
                    )
                }.forEach {
                    println("${it.title} : ${it.libraryName}")
                }
    }
1 Like

What is the type of person?

This is the declaration that I want to, it should be same as

val person = object {
val name = “John”
val age = 28
}

OK, I misunderstood.
How you can distinguish val from var then?

I think it should be val implicitly.

And why is that? The syntax you propose does not introduce anything new and just complicates things.

Do you really use anonymous objects frequently? I did not even knew that you can omit type because I never encountered the need to use it this way.

It looks like a few (private?) data classes will help here:

data class LibrarySongOwnership(val title: String, val libraryName: String)

It results in about the same code length as your preferred syntax:

newContext {
   from(Songs join Libraries on { x, y -> x.libraryId eq y.id })
           .where { (_, library) -> library.continuous eq true }
           .select { (song, library) -> LibrarySongOwnership(song.title, library.name) }
           .collect { LibrarySongOwnership(it.get { title }, it.get { libraryName }) }
           .forEach {
               println("${it.title} : ${it.libraryName}")
           }
}
1 Like

This way one has to invent a lot of names for the entities that are better to remain anonymous.

These classes most likely would become one-shot, i.e. used in a single query. Declaring them besides the query is a boilerplate and an obstacle both for writing and reading the code.

2 Likes

Am I understanding it correctly if the idea is to allow anonymous (single-use) tuples (or structs if you want to call them that way)? I can see it’s value, although the right syntax is a bit elusive (how do you specify the member names).

In particular you want something to improve over the use of pair (or another function that returns a generic tupple) – Straight replacement:

    newContext {
        from(Songs join Libraries on { x, y -> x.libraryId eq y.id })
                .where { (_, library) -> library.continuous eq true }
                .select { (song, library) -> Pair(song.title, library.name) }
                .collect { Pair(
                            it.get { first } ,
                            it.get { second }
                    )
                }.forEach {
                    println("${it.first} : ${it.second}")
                }
    }

I know pair is specific for two values, but an overloaded tuple function could be used for any number of parameters. The forEach could instead read forEach { (title, libraryName) -> /*...*/ }.

I know that a tupple is a fixed structure that will be reference based (and generic), but perhaps it is good enough (optimization is to the compiler, as long as the language provides enough information).

This makes this proposal combine with collection-literals, doesn’t it?

https://github.com/Kotlin/KEEP/pull/112