Translate API response to nullable String - oop

An API I consume returns (among other fields) a mandatory telephone1 and an optional telephone2. However, the JSON I fetch always contains both fields and a missing entry is displayed as an empty string.
{
"telephone1": "+1 555 1234",
"telephone2": ""
}
When the response is mapped to a pojo, is it preferable to translate the empty string to null? Such that:
data class(
val telephone1: String,
val telephone2: String?
}
To me, this better communicates the possible states. Should I, though? Are there drawbacks?

At the first sight, problem boils down to different checks before further data processing: x == null or x.isEmpty(). But while nullability check is generally enforced by kotlin compiler (unlike unemptiness), it seems to be a better option.
But there are still some situations when usage of null (without any compiler errors) may lead to problems in runtime (mainly related to interop with languages without enforced nullability): like implicit convertion of null to literal string "null" (when concatenating with another string), or even NPE when passed to method accepting String! (platform type) and not annotated properly.
Sticking to DDD principles, the better option would be declaration of separate datatypes:
sealed class OptionalPhoneNumber
data class PhoneNumber(val value: String) : OptionalPhoneNumber() //You may also add some checks in init block that `value` is really a phone number, not just a set of random chars
object EmptyPhoneNumber : OptionalPhoneNumber()
and defining your data class as:
data class Data (
val telephone1: PhoneNumber,
val telephone2: OptionalPhoneNumber
)
Type system will enforce you to do x is PhoneNumber checks, and thanks to smart casts it's further usage will be type-safe:
if (telephone2 is PhoneNumber) {
println(telephone2.value)
}

Related

Is it possible to pass null type in place of generic type parameter?

I am going to use the following method from Spring Data Kotlin extensions:
inline fun <reified T : Any> MongoOperations.bulkOps(bulkMode: BulkMode, collectionName: String? = null): BulkOperations
The question is: can I somehow avoid specifying T assuming I do not want to provide entity class name (that's because I will explicitly specify collectionName, and in this case class type can be null). I would like to type something like:
val ops = mongoTemplate.bulkOps<null>(BulkOperations.BulkMode.UNORDERED, collectionName = "i_know_better")
Is there a type literal for null with which I can parameterize bulkOps?
I think the short answer is no.
You seem to confuse types with values. null is a value and not a type so it cannot be used as a type in generic methods.
In your specific example, even if you could use null, looking at the code what would you expect to happen?
#Suppress("EXTENSION_SHADOWED_BY_MEMBER")
inline fun <reified T : Any> MongoOperations.bulkOps(bulkMode: BulkMode, collectionName: String? = null): BulkOperations =
if (collectionName != null) bulkOps(bulkMode, T::class.java, collectionName)
else bulkOps(bulkMode, T::class.java)
As you can see there's always T::class.java being called. What would be the result of null::class.java?
I'm unfamiliar with the Spring Data so I can't really provide an alternative, but I'd say you either need to search for another method or use an appropriate class here. The generic type is marked as T : Any so presumably it can be any non-nullable type. I wonder if Unit would work. Again, I'm not sure what this class is used for.
To answer the question in general, you can use Nothing? to represent the type that only contains the value null.
That being said, as #Fred already said, the method you're considering here explicitly states T : Any, meaning only non-nullable types are allowed. And it makes sense given that the function is accessing the class of T.

Referential vs Structural equality in Kotlin in case of strings

My current understanding of structural equality is that it compares the type and the content.
For Referential equality, it compares the address of the two objects. Also, in the case of a primitive type of var, it will print true if the content is the same.
According to the doc here --> numbers, characters and booleans can be represented as primitive values at runtime - but to the user, they look like ordinary classes.
So String should be treated as objects at runtime.
But I get true when comparing referentially two strings that have the same content.
fun main(){
val name1 = "123"
val name2 = "123"
println(name1 == name2) //true, structural equality which is same type and same content (same as equals)
// checks if left and right are same object --> referential equality
var name3 = "123"
println(name1 === name3) //true ????????
// should print false. String is basic type and not primitve
var Arr: IntArray = intArrayOf(1,2,3)
var Arr2: IntArray = intArrayOf(1,2,3)
println(Arr === Arr2) // prints false, arrays are basic type
}
Also, why doesn't equality in kotlin of both types differentiates between val and var? They are two different types of objects at their core.
Can someone point out where am I going wrong with this? I might be missing something pretty obvious here.
So as far as string referential equality check goes, I think it does the same thing as Java in that it adds everything to the string constant pool.
Here is the thread for referential string comparison in java (done by ==) -
What makes reference comparison (==) work for some strings in Java?
For Val vs Var the answer by #Tenfour04 below explains the logic.
val and var are not different types of objects. They are references, not objects at all. They have nothing to do with the behavior of the objects they are referring to. When you compare two objects, the types of variables and properties that are referencing them is not a factor whatsoever. When you call equals on one object, the runtime only uses the reference to find the object in memory. Only then is its function called.

Map of generic interfaces in Kotlin

I stuck with some simple thing) Let's say I have following:
interface IMessagePayload // marker interface
data class IdPayload(
val id: Long
) : IMessagePayload
data class StringPayload(
val id: String,
) : IMessagePayload
Then I have a class:
data class Message<T : IMessagePayload>(
val id: String,
val payload: T,
)
Also I have some interface describing processor of this message:
interface IMessageProcessor<T : IMessagePayload> {
fun process(message: Message<T>)
}
And some implementation:
class ProcessorImpl : IMessageProcessor<IdPayload> {
override fun process(message: Message<IdPayload>) {
}
}
Now I wanna have a map of such processors. Lets use some enum type as a keys of this map:
enum class ActionType {
UPDATE,
DELETE,
ADD
}
private var map = mutableMapOf<ActionType, IMessageProcessor<IMessagePayload>>()
map[ActionType.ADD] = ProcessorImpl() // <-- error here
And that's where the problem occurs. I cannot put my ProcessorImpl into this map. The compiler says that there is an error: Type mismatch. Required: IMessageProcessor. Found: ProcessorImpl().
I could declare the map in the following way (using star projection):
private var map = mutableMapOf<ActionType, IMessageProcessor<*>>()
But in this case I cannot call processors's process method fetching it from the map by key first:
map[ActionType.ADD]?.process(Message("message-id", IdPayload(1))) // <-- error here
Compiler complains: Type mismatch. Required nothing. Found Message<IdPayload>
What am I doing wrong? Any help is appreciated.
This is about variance.
IMessageProcessor is defined as interface IMessageProcessor<T : IMessagePayload>; it has one type parameter, which must be IMessagePayload or a subtype.
But it is invariant in that type parameter; an IMessageProcessor< IdPayload> is not related to an IMessageProcessor<IMessagePayload>.  In particular, it's not a subtype.
And your map is defined with a value type IMessageProcessor<IMessagePayload>.  So its value cannot be an IMessageProcessor< IdPayload>, because that's neither the value type, nor a subtype.  Hence the compile error.
In this case, the simplest way to get it to compile is to change your map:
private var map = mutableMapOf<ActionType, IMessageProcessor<out IMessagePayload>>()
The only difference there is the out; that tells the compiler that the value IMessageProcessor is covariant in its type parameter.  (It may help to think of out as meaning ‘…or any subtype’.  Similarly, you could make it contravariant by using in, which you might think of as ‘…or any supertype’.)
This lets you store in the map an IMessageProcessor for any subtype of IMessagePayload.
However, if you do that, you'll find that you can't use any value you pull out of your map — because it can't tell which messages the processor can handle, i.e. which subtype of IMessagePayload it works for!  (The compiler expresses this as expecting a type parameter of Nothing.)
In general, it's often better to specify variance on the interface or superclass itself (declaration-site variance) rather than the use-site variance shown above.  But I can't see a good way to do that here, because you have multiple generic classes, and they interact in a complicated way…)
Think for a moment what IMessageProcessor's type parameter means: it's the type of message that the processor can consume. So an IMessageProcessor<A> can handle messages of type Message<A>.
Now, a subtype must be able to do everything its supertype can do (and usually more) — otherwise you can't drop that subtype anywhere that's expecting to use the supertype.  (That has the grand name of the Liskov substitution principle — but it's really just common sense.)
So an IMessageProcessor<B> is a subtype of IMessageProcessor<A> only if it can handle at least all the messages that an IMessageProcessor<A> can.  This means it must accept all messages of type Message<A>.
But Message is invariant in its type parameter: a Message<B> is not directly related to a Message<A>.  So you can't write a processor that handles them both.
The most natural solution I can find is to specify variance on both Message and IMessageProcessor:
data class Message<out T : IMessagePayload>( /*…*/ )
interface IMessageProcessor<in T : IMessagePayload> { /*…*/ }
And then use a wildcard in your map to make it explicit that you don't know anything about the type parameters of its values:
private var map = mutableMapOf<ActionType, IMessageProcessor<*>>()
That lets you safely store a ProcessorImpl() in the map.
But you still have to use an (unchecked) cast on the values you pull out of the map before you can use them:
(map[ActionType.ADD] as IMessageProcessor<IdPayload>)
.process(Message("4", IdPayload(4L)))
I don't think there's any easy way around that, because the problem is inherent in having values which are processors that can handle only some (unknown) types of message.
I'm afraid the best thing would be to have a rethink about what these classes mean and how they should interact, and redesign accordingly.

toString() in Kotlin - wrong output

I have written some codes for printing out objects in array with toString()
but by using Option1 println(path.toString())
Output is [LRunningpath;#27973e9b
which is not what i want. Then i replace it with Option2 as follow
var i=0
for(i in 0 until path.size)
println(path[i].toString())
which is correct.
My questions are,
why Option 1 don't work?
what does the output in Option 1 mean?
any advice to avoid the same situation in the future?
Any hints is very appreciated. Thank you for the kindness.
my codes are as below:
fun main() {
println("Warming up")
val input1 = Runningpath("in Forest", 2000, "some houses")
val input2 = Runningpath("at lake", 1500, "a school")
val path = arrayOf(input1, input2 )
println(path.toString())
/* var i=0
for(i in 0 until path.size)
println(path[i].toString())
*/
}
class Runningpath(val name: String, val length: Int, val spot: String){
override fun toString(): String= "The Path $name ($length m) is near $spot"
}
Short answer: in most cases, it's better to use lists instead of arrays.
Arrays are mostly for historical reasons, for compatibility, and for implementing low-level data structures.  In Kotlin, you sometimes need them for interoperability with Java, and for handling vararg arguments.  But other than those, lists have many advantages.
The problem is that on the JVM, an array is very different from all other objects.  It has only the methods inherited from Object, and doesn't override those.  (And you can't create your own subclasses to override or add to them.)
In particular, it has the toString() method from Object.  That gives a code indicating the type — here [ for an array, L indicating that each element is a reference, Runningpath giving the type of reference, ; and # separators, and a hex representation of the array's hash code, which may be its address in memory or some other unique number.
So if you want some other way of displaying an array, you'll have to do it ‘manually’.
Other problems with arrays on the JVM result from them having run-time typing — they were part of Java long before generics were added, and interoperate badly with generics (e.g. you can't create an array of a generic type) — and being both mutable and covariant (and hence not type-safe in some cases).
Lists, like other Collections and data structures, are proper objects: they have methods such as toString(), which you can override; they can have generic type parameters; they're type-safe; they can have many implementations, including subclasses; and they're much better supported by the standard library and by many third-party libraries too.
So unless you have a particular need (vararg processing, Java interoperability, or a dire need to save every possible byte of memory), life will go easier if you use lists instead of arrays!
You can use the joinToString for that:
println(path.joinToString("\n"))
The joinToString() is actually available for both the List and the Array, but I'd recommend using the List as you'd have immutability and many other extensions on that, that will help your on manipulating the datas.

Corda State Evolution - nullable vs. default properties

In Corda, adding new properties to states (state evolution) requires that new properties are nullable in order to remain backwards compatible with previous versions of the state.
data class Version1DummyState(
override val participants: List<AbstractParty>
) : ContractState
data class Version2DummyState(
override val participants: List<AbstractParty>,
val myNewProperty: String? = null
) : ContractState
Since Kotlin also supports properties with default values, I'd like to know why state evolution is restricted to properties of nullable types only, but not non-nullable properties, provided that those properties have a default value?
data class Version2DumyState(
override val participants: List<AbstractParty>,
val myNewProperty: String = "Hello, world."
) : ContractState
My rationale for asking this came from looking at the implicit upgrade sample, in which the obligation state is upgraded to allow the obligor to default on their obligation. true and false accurately represent whether the obligor has defaulted, but null does not. The ability to upgrade with a default value of false seems more natural than using a nullable field.
I think you can make that work by marking the constructor with #JvmOverloads like this:
data class DummyState #JvmOverloads constructor(
override val participants: List<AbstractParty>,
val myNewProperty: String = "blah"
) : ContractState
(don't put version numbers into state class names)
The #JvmOverloads makes the "old" constructors visible to the deserialisation engine for matching.
But, it's probably better to be explicit here with a line of code like:
val inDefault: Boolean get() = myNewProperty ?: false
or
fun priceOr(default: Amount<Currency> = 0.USD) get() = price ?: default
if you really want this.
Backwards compatibility and default values need to be treated quite carefully. A common mistake is to use a default value of zero/empty string/false for newly introduced fields, even when those values are semantically meaningful to the app. That is, knowing that the old message didn't specify something is valuable information that shouldn't be lost or replaced with fragile sentinel values. Consider the new field "price". Prices can't be negative, so perhaps a developer sets a default value of zero. But pricing something as free is a meaningful thing to do - maybe not in today's business scenario, but perhaps tomorrow? Now you have a problem.
Kotlin's type system and syntax is very good at dealing with missing values. It's so easy to substitute a default at the use-site using the ?: operator, I'd be worried about establishing a convention of always supplying a default at the construction site that junior devs follow without being aware of the potential consequences. Explicitly exposing the fact that a default may be substituted forces people to think about whether that's really logical.