Is there a simpler form of `(x != null && ...
# getting-started
k
Is there a simpler form of
(x != null && y == null) || (x == null && y != null)
?
r
If i am not mistaken it’s an xor
👍 2
k
(x == null) xor (y == null)
is a simpler form, but what is your use case? It sounds like it can be made simpler than that, possibly using null-safety features. Are you, for instance, trying to get whichever of the two is not null?
👍 2
k
I want a data class to only init if they are different (in terms of null)
So only one should be not null
r
I hate it when people do this, but... Are you sure it isn't really two classes? Perhaps with a sealed supertype?
Copy code
sealed interface Super {
  val x: String?
  val y: String?
}

data class X(override val x: String): Super {
  override val y: String? = null
}

data class Y(override val y: String): Super {
  override val x: String? = null
}
2
j
@Rob Elliot I would even go so far as saying
x
and
y
shouldn't even be in the
Super
interface at all
👍 3
If you don't want to make it a sealed class, why not just
(x == null) != (y == null)
?
xor
seems quite bitwise-y if you ask me
m
So I believe I am aware of the type of case you're looking for. When I have that case, I find a function to explicitly check the domain of the variables is a more flexible solution if I don't care which is null when initializing the class. If I do care which is null, then you can do pattern matching usually to make it look very explicit and match the logic up cleanly with the case (x==null or y== null)
Copy code
when {
  x==null && y!=null -> println("y is lone int")
  y==null && x!=null -> println("x is lone int")
  else -> println("ignore the domain issue")
}
s
@Joffrey I would even go so far as saying
x
and
y
shouldn't even be in the subclasses.
Copy code
sealed interface Super
data class X(override val x: String): Super
data class Y(override val y: String): Super
j
@Stephan Schroeder this code doesn't compile, and
x
and
y
are in the subclasses in your example... so I don't get your point 🤔 How would you store the data of
x
and
y
at all if not in the subclasses?
Oh I think you were talking about "the other x and y" - got it. Yeah this was my initial point, the only reason the null "other ones" are in each subclass is to accommodate for the superinterface having both variables. If it doesn't, then of course
x
and
y
should only be in their respective subclass
k
Do I need to add anything to the sealed interface to make Jackson correctly deserialize it?
s
ah, yeah the
override
is no longer needed, my bad. I have no idea how sealed classes behave in serialisation 😐 If that's your usecase maybe use a data class after all, but you can make sure the x!=null xor y!=null constraint is guaranteed
Copy code
data class XOrY private constructor(
	val x: String? = null,
    val y: String? = null,
) {
    companion object {
		fun fromX(x: String) = XOrY(x=x)
        fun fromY(y: String) = XOrY(y=y)
        fun from(x:String?, y:String?): XOrY {
            require((x==null) xor (y==null))
            return XOrY(x,y)
        }
    }
}
j
@Kenneth I'm not sure about
sealed interface
(since the feature is quite recent), but I'm sure that `jackson-module-kotline`s supports sealed classes. So at worst you would just have to use a sealed class instead
r
You can ask about it in #jackson-kotlin. I'm pretty sure you have to indicate to Jackson how to disambiguate the type, which might be as simple as "if it has a field
x
use type
X
otherwise type `Y`" - have a look at https://www.baeldung.com/jackson-inheritance For Jackson
FAIL_ON_UNKNOWN_PROPERTIES
is
true
by default, so it would fail if
x
and
y
were both present.