Short form for anonymous objects


#1

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}")
                }
    }

#2

What is the type of person?


#3

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

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


#4

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


#5

I think it should be val implicitly.


#6

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.


#7

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}")
           }
}

#8

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.


#9

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).


#10

#11

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