Is it possible to have properties other than those generated automatically in a data class?

Asked

Viewed 171 times

6

Kotlin allows you to simplify the creation of what in Java we call POJO:

data class Person(val firstName: String, val lastName: String)

With this we get a class with the getter for all variables declared in the constructor and methods equals(), toString(), copy(), among others.

My question is whether it is possible to add other properties. For example in the class Person add/declare the property fullName: String.

  • Add new properties? How would you think about doing that? In itself? Isn’t just changing the font? Of course you may have problems if it has already been used in some code, as in any class. Creating a new one based on this cannot. What I’m trying to see is if it gives to put non-standard behaviors in it.

  • @bigown Did not think, the premise was the language allow. And through Extension Properties is possible?

  • I got it, I gotta find out.

  • @ramaral, you can also create properties that originate from others, either by delegation or even at construction time.

  • @Wakim You can illustrate how?

  • This must be the 98th time that this very same question reaches the front page with title and content changed. What’s going on? Needless to say!

  • @Can Tonymontana explain what you’re getting at? The title has never been changed and the two changes were minimal. The first, to focus the question only on the addition of properties (POJO by definition has no behavior), the second, to make it coherent with the code (with val is not generated Setter).

  • 1

    From what I see the right answer has not yet appeared hehe. What answers @ramaral’s question is that data class is a class like any other, with a few restrictions. All the others, including mine, don’t address this, talk about extensions and properties generated about others. If so, it would be better to have an answer with that content.

  • @Wakim You are right. I think the only restriction is that it cannot be inherited. As far as I can tell, it’s possible to pick up any class you already have keyword data and everything works, receiving "free" these automatic methods. I may be wrong, and I’m sorry if I am, but what happened was that the answers were originally a little hasty and somewhat lacking in knowledge. They went after me for mentioning the possibility of using Extension Properties, however the bigown already approaches it. I suggest you edit your answer accordingly.

  • @Wakim Note that the bigown refers, in a commenting, that "this is being excellent learning"

Show 5 more comments

3 answers

4

Yes, it is possible. One way to do this is through of extensions.

One can create both functions and properties in this way.

To declare an extension, you need to prefix its name with the type being extended.

To keyword this is valid within extension functions and is used to refer to the "receiver" object (which is extended).

Extension properties do not support the use of backing Fields.

See a full example

fun main(args: Array<String>) {
    val per = Person("Linq", "Bueno")
    println(per.obterFullName())
    println(per.fullName)
}

fun Person.obterFullName() = "${this.firstName} ${this.lastName}"
// ^ Isto é uma função de extensão

val Person.fullName: String
  get() = "${this.firstName} ${this.lastName}"
// ^ Isto é uma propriedade de extensão    

data class Person(val firstName: String, val lastName: String)

See working here.

2


It is possible to create property extensions, and in the example quoted it should work because I believe that in the background it is not a property, to tell the truth or I don’t really like the name, because I think that property implies having a state field linked, which is not very the case. Then you can create a method getter and even a Setter depending on what you want to do and the usage syntax will be equal to that of a field, but it cannot have an associated state field, so the answer is yes to the behavior and not to the state.

You can add behaviors and even extra states to your own data class also, but they will not be part of the basic class structure, for example a property that is not in the primary constructor does not enter the equals(), or toString().

fun main(args: Array<String>) {
    val pessoa = Person("João", "Silva")
    pessoa.age = 47
    println(pessoa.fullName)
    println(pessoa.Firula())
    println(pessoa.firula)
    val pessoa2 = pessoa.copy()
    println(pessoa2.age)
    pessoa2.age = 40
    println(pessoa2.age)
    println(pessoa == pessoa2)
    println(pessoa2)
}

data class Person(val firstName: String, val lastName: String) {
    fun Firula(): String = "O nome dele é " + firstName + " " + lastName
    val firula: String
        get() = "O nome dele é " + firstName + " " + lastName
    var age: Int = 0
    override fun toString() = firstName + " " + lastName
}

val Person.fullName: String
    get() = firstName + " " + lastName

Behold working in the ideone. And in the Kotlin Play. Also put on the Github for future reference.

Of course it is possible to extend with functions also that only has behavior.

Just note that the extension occurs statically, has nothing of inheritance in this extension. So they’re just facilitators, it doesn’t change the class structure, whether it’s a data class or a normal class.

  • So, it is possible to add functions but not properties?

  • So, it is possible to add properties that are not quite properties :) For me this kind of property is just a function because it has not been, but the access syntax is a property. I find it confusing terminology because there are two types of properties, one with a state and the other without a state. There’s a different semantics between them and I think it’s almost slutty to have the same name.

  • You are referring to the property extensions?

  • Let’s also look at what the term is add used. If it is in the own data class I think you can add both, because the stateless property is a function or pair of functions. I can check if it gives everything and I think it even gives (I would need to confirm), of course that if you create a property with status within the data class it would not be included in the automatically generated methods. At least the intuition says so.

  • Yes, the idea was to know if it was possible to add to the class itself, in the background as you did with the function Firula().

  • @ramaral was even yes, but whatever. What’s different about the extension is that it can never have been and within the class may or may not.

  • Yes I know that, so I suspected that you were referring to them.

  • 1

    I changed the example, I think I now cover all items, but if not, let me know, this is being excellent learning and will serve for C# when you have the same. The only disgrace of Kotlin is that the compiler is slow that hurts.

  • Now it is. Deep down the question was whether the declaration of data class was restricted to that form (perhaps I should reform it). By your answer I see that it is allowed to open square brackets and declare functions and properties as in any class.

Show 4 more comments

2

Complementing the excellent responses, you can create immutable properties based on existing ones.

Either at initialization/declaration:

data class Person(val firstName: String, val lastName: String) {
    val fullName = "$firstName $lastName"
}

If it makes more sense for organization (of course if the boot is small we don’t need to use the init):

data class Person(val firstName: String, val lastName: String) {
    val fullName: String

    init {
        fullName = "$firstName $lastName"
    }
}

Or via Lazy instantiation:

data class Person(val firstName: String, val lastName: String) {
    val fullName: String by lazy { "$firstName $lastName" }
}
  • Instead of "on startup" it should not be "on declaration"?

  • 2

    Yes and no hehe. That snippet of code is executed on class startup, but ta on the same statement.

  • You’re right, the property is declared and initialized at the same time. I was thinking in terms of the class.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.