Kotlin Data Class Wildcard I'm writing a small custom DSL and interpreter as an exercise in understanding how the language stack (lexer/parser/(interpreter/compiler)) works. Because I want to be able to report the location of semantic errors, the AST needs to retain information about where the elements were in the source.

For this purpose I wrote a data class Point(val line: Int, val column: Int). All well and good, until I realized that manually specifying the position of EVERY node in the AST for unit tests on parsing would be prohibitively time consuming (and error prone). (Obviously, some tests need to do so to test the assigning of positions, but some is a lot fewer than all.)

To allow me to write more good unit tests quicker, I decided I wanted to default the position of all my nodes to a wildcard value that would match all valid Points. The parsed nodes would have the correct position, but the manually assembled AST to check against would not specify (and thus not test) the positions. This is the solution I came up with.

/**
 * DO NOT EXTEND THIS CLASS!!
 *
 * This is an custom open data class to allow a wildcard value.
 */
open class Point(val line: Int, val column: Int) {
    object Wildcard : Point(-1, -1) {
        override fun toString() = "Point.Wildcard"
        override fun copy() = this
    }

    override fun equals(other: Any?) = when {
        this === other         -&gt; true
        other === Wildcard     -&gt; true
        other !is Point        -&gt; false
        this === Wildcard      -&gt; true
        line != other.line     -&gt; false
        column != other.column -&gt; false
        else                   -&gt; true
    }

    override fun hashCode(): Int { // generated
        var result = line
        result = 31 * result + column
        return result
    }

    override fun toString() = "Point(line=$line, column=$column)"
    operator fun component1() = line
    operator fun component2() = column
    open fun copy() = Point(line, column)
}


I wanted to keep all the behavior of a data class, but a data class cannot be open and this was the only way I could come up with of implementing the wildcard value. This solution still feels wrong and too much like a hack, however. It could easily be broken by outside code extending Point (as it must necessarily be available to be used) and so much of this code is just re-implementing what data class gives us for free. I feel like there must be a solution with a sealed class, but I haven't figured it out.

Recommended review points: idiomaticness (or not) of code, conventions, alternate solutions (and any other points)
Your equals method is not transitive (e.g. Point(2, 2) == Point.Wildcard and Point.Wildcard == Point(3, 3) but Point(2, 2) != Point(3, 3). See Any.equals - stdlib - Kotlin Programming Language for more details on the requirements for equals. You might also consider using EqualsTester from guava-testlib for testing your own implementations of equals.

If you define your own method instead of defining a custom, non-transitive equals implementation than your existing solution can become much simpler:

data class Point(val line: Int, val column: Int) {
    companion object {
        val wildcard = Point(-1, -1)
    }

    infix fun matches(other: Point): Boolean {
        return this == other || other === wildcard || this === wildcard
    }
}


Notes:


Point(2, 2) matches Point(-1, -1) will return false.
Point(2, 2) matches Point.wildcard will return true.
If you want both to return true then replace the === with == in matches.
Marking matches as infix is purely optional but it seems to me like a good fit.