2

I have a few data classes, that is short, so I group them together in a file.

I can defined them in a Kotlin file as it is, but would prefer it to be scope within a class/object, so the file is not just a file, but under class/object for better grouping

I could do

object Model {
    data class Result(val query: Query)
    data class Query(val searchinfo: SearchInfo)
    data class SearchInfo(val totalhits: Int)
}

and I could also do

class Model {
    data class Result(val query: Query)
    data class Query(val searchinfo: SearchInfo)
    data class SearchInfo(val totalhits: Int)
}

They both looks the same to me. What's the different, and if there's a preferred way in term of scoping my data classes?

Elye
  • 53,639
  • 54
  • 212
  • 474

2 Answers2

3

I would advise against using classes for scoping other classes. As Todd explains in his answer, you can use sealed classes which offer an actual benefit of exhaustive when checks. If you don't need this feature, Kotlin has a built-in mechanism for scoping - packages:

package org.company.model

data class Result(val query: Query)
data class Query(val searchinfo: SearchInfo)
data class SearchInfo(val totalhits: Int)

I can defined them in a Kotlin file as it is, but would prefer it to be scope within a class/object, so the file is not just a file, but under class/object for better grouping

There's nothing wrong with a file containing multiple top-level elements. This is a useful language feature and is used in exactly this kind of situation.

Kirill Rakhman
  • 42,195
  • 18
  • 124
  • 148
  • Hi Kirill, Thanks for the answer. I agree, there's no issue having it as top level. However, I'm using Retrofit 2 and proguard, that some how the proguard would obfuscate it causing compilation error, So I scope it o that I could keep the classes as per https://stackoverflow.com/a/44473703/3286489 without need to keep them individually – Elye Jun 11 '17 at 05:41
  • 1
    If you put your model classes in subpackage, you can instruct ProGuard to keep just that subpackage. – Kirill Rakhman Jun 11 '17 at 16:51
0

Another option is to make all of your data classes a subclass of a sealed Model class. This will give you the benefit of defining them all in one place, because Kotlin enforces that for sealed classs. Also, having the type system know about all instances of type Model is helpful in when expressions as well because then it won't require you to put an else -> block.

sealed class Model
data class Result(val query: Query) : Model()
data class Query(val searchinfo: SearchInfo) : Model()
data class SearchInfo(val totalhits: Int) : Model() 

And you can just use them directly:

val r = Result(Query(SearchInfo(3))

Instead of wrapping them in another class or object, where you'd have to refer to them like this:

val r = Model.Result(Model.Query(Model.SearchInfo(3)))
Todd
  • 30,472
  • 11
  • 81
  • 89