I want to print out labels of spices in SpiceContainer but I get
Here is my code. How do I solve this?
package Spice
fun main(args: Array<String> ) {
jack()
}
class Spice(){
val name:String=("Curry")
val spiciness:String=("mild")
}
data class SpiceContainer(var spice: Spice){
val label=spice.name
}
fun jack(){
val spiceCabinet = listOf(SpiceContainer(Curry("Yellow Curry", "mild")),
SpiceContainer(Curry("Red Curry", "medium")),
SpiceContainer(Curry("Green Curry", "spicy")))
for(element in spiceCabinet) println(element.label)
}
You are trying to create an instance of a class Curry you just don't have. Instead, you have a class Spice with a name and a spiciness. If you want an instance of, say Red Curry, you would have to instantiate a Spice and give it the desired name: Spice("Red Curry", "kinda hot").
A good practice for that spiciness (at least a better one than just a String) would be an enum class Spiciness...
Here's a simple example:
// a spice consisting of a name and some degree of spiciness
data class Spice(val name: String, val spiciness: Spiciness)
// the spice container that gets the label of the spice contained
data class SpiceContainer(val spice: Spice) {
val label: String = spice.name
}
// enumerate possible degrees of spiciness
enum class Spiciness {
NONE_AT_ALL,
MILD,
MODERATE,
HOT,
DANGEROUSLY_HOT,
LIFE_THREATENING,
UNKNOWN_TRY_YOURSELF
}
fun jack() {
// create a list of spices and add some arbitrary ones
val spiceCabinet = listOf(SpiceContainer(Spice("Yellow Curry", Spiciness.MODERATE)),
SpiceContainer(Spice("Red Curry", Spiciness.HOT)),
SpiceContainer(Spice("Green Curry", Spiciness.UNKNOWN)),
SpiceContainer(Spice("Pepper", Spiciness.MILD)))
// print each item's label
spiceCabinet.forEach{ it -> println(it.label) }
}
and run the fun jack() like this
fun main() {
jack()
}
in order to get an output of
Yellow Curry
Red Curry
Green Curry
Pepper
I don't really get why you need or want the SpiceContainer, but that's beyond the scope of this answer (and question, most likely).
Related
Suppose I have
data class NonComparable(val a : Any) //i.e. does not implement Comparable
data class WrappingElement(val nc : NonComparable)
val unordered = listOf<NonComparable>(....)
val comparator = Comparator<NonComparable>(){...}
What is the cleanest (least lines of code) way of sorting unordered with comparator?
In other words: How to reuse the logic in comparator (for NonComparable) to order a list of WrappingElements?
Given you have a custom Comparator you want to reuse, like below:
object NonComparableComparator: Comparator<NonComparable> {
override fun compare(p0: NonComparable, p1: NonComparable): Int {
// your custom comparision logic here ...
}
}
val comparator = NonComparableComparator
There is nothing stopping you to re-use this comparator in a Comparator for the wrapping element.
val wrappingElementComparator = Comparator<WrappingElement> {
p0, p1 -> comparator.compare(p0.nonComparable, p1.nonComparable)
}
val sortedList = unsortedList.sortedWith(wrappingElementComparator)
All code above is based on the following:
data class NonComparable(val value: Any?)
data class WrappingElement(val nonComparable: NonComparable)
val unsortedList = listOf(
WrappingElement(NonComparable(3)),
WrappingElement(NonComparable(2)),
WrappingElement(NonComparable(4)),
WrappingElement(NonComparable(5)),
WrappingElement(NonComparable(0)),
WrappingElement(NonComparable(1)),
)
I'm using jackson-module-kotlin:2.11.2 to parse some YAML. I'm trying to produce objects which contain a map, whose values are objects of a class that I have declared. This map instead contains values which are HashMaps.
Here are my declarations:
import com.fasterxml.jackson.module.kotlin.readValue
object Parser {
// ObjectMapper is thread safe as long as we don't mess with the config after this declaration.
val mapper: ObjectMapper = ObjectMapper(YAMLFactory()).registerKotlinModule()
.registerModule(JavaTimeModule())
.registerModule(nullMapDeserialiserModule)
.registerModule(SimpleModule().setDeserializerModifier(ValidatingDeserializerModifier()))
// When parsing timestamps, we don't want to lose the offset information
.disable(DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE)
// We would prefer an error if we're trying to store a float in an int
.disable(DeserializationFeature.ACCEPT_FLOAT_AS_INT)
// If a primitive field (like Int) is non-nullable (as in the Kotlin meaning), then we don't want nulls being converted to 0
.enable(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES)
// Because enums could change order in future versions (if we keep them in lexicographic order, for example),
// we don't want the client to expect that they can give us the ordinal value of the enum.
.enable(DeserializationFeature.FAIL_ON_NUMBERS_FOR_ENUMS)
// When serialising schedule expressions, don't include null values
.setSerializationInclusion(JsonInclude.Include.NON_NULL)
#Throws(JsonProcessingException::class)
inline fun <reified T: Any> deserialise(yaml: String): T = mapper.readValue(yaml)
}
data class ListValue (
val listValueKey: String,
val someOtherValue: Int
)
data class ExpectedValue (
val expectedValueKey: String,
val list: List<ListValue>
)
data class TestClass (
val testClassKey: String,
#param:JsonDeserialize(contentAs = ExpectedValue::class)
val testMap: Map<String, ExpectedValue>
)
Here is my test case:
#Test
fun `map parse test`() {
val testObj: TestClass? = RuleParser.deserialise(
//language=YAML
"""
testClassKey: the-key
testMap:
key1:
expectedValueKey: subKey1
list:
- listValueKey: someKey1
someOtherValue: 5
- listValueKey: anotherKey1
someOtherValue: 6
key2:
expectedValueKey: subKey2
list:
- listValueKey: someKey2
someOtherValue: 7
- listValueKey: anotherKey2
someOtherValue: 8
"""
)
assertTrue(testObj is TestClass)
assert(testObj.testMap is HashMap)
assertNotNull(testObj.testMap["key1"])
assert(testObj.testMap["key1"] is ExpectedValue)
assertEquals(
ExpectedValue(
expectedValueKey = "subKey1",
list = listOf(ListValue("someKey1", 5), ListValue("anotherKey1", 6))
),
testObj.testMap["key1"]
)
}
Currently, this test is failing on the final assertion, with the following error
Expected :ExpectedValue(expectedValueKey=subKey1, list=[ListValue(listValueKey=someKey1, someOtherValue=5), ListValue(listValueKey=anotherKey1, someOtherValue=6)])
Actual :{expectedValueKey=subKey1, list=[{listValueKey=someKey1, someOtherValue=5}, {listValueKey=anotherKey1, someOtherValue=6}]}
This is clearly not what I expected. If I instead parse a list of a declared class, this works correctly (example test follows).
#Test
fun `list parse test`() {
val testObj: ExpectedValue? = RuleParser.deserialise(
//language=YAML
"""
expectedValueKey: subKey1
list:
- listValueKey: someKey1
someOtherValue: 5
- listValueKey: anotherKey1
someOtherValue: 6
"""
)
assertTrue(testObj is ExpectedValue)
assertTrue(testObj.list[0] is ListValue)
assertEquals(
ListValue("someKey1", 5),
testObj.list[0]
)
}
So I'm a bit surprised that it is possible to parse a generic list in this way, but not a map. How do I get Jackson to create the map values that I expect, rather than HashMaps?
Your deserializer function is wrong. You must use the reified generic type in readValue method:
inline fun <reified T: Any> deserialise(yaml: String): T = mapper.readValue(yaml, T::class.java)
While it is odd that the annotation is needed at all (since it is not needed for lists of a declared type), it does work if the annotation is used as follows:
#field:JsonDeserialize(`as` = HashMap::class, contentAs = ExpectedValue::class)
This was not clear at first, because that javadoc for contentAs does not mention that as is also required.
first, I'm a kotlin neebie ^^.
I want to compare to objects from a data class. But the objects have variables that can be changed.
Is the code example a good practice to solve this or is there a problem that i can't see?
Ty
data class Test1(val id : Int, var name: FlexibleProperty<String>)
class FlexibleProperty<T>(var value: T) {
override fun equals(other: Any?) = true
override fun hashCode() = 1
}
fun main() {
val test1 = Test1(1, FlexibleProperty("Hans"))
val test2 = test1.copy()
println("test1 == test2 ${test1 == test2}")
println("test1 === test2 ${test1 === test2}")
test2.name = FlexibleProperty("Dieter")
println("test1 == test2 ${test1 == test2}")
println("test1 === test2 ${test1 === test2}")
}
EDIT:// Sry, I was a little confused ^^. My detailed problem is: I want to add these objects into a set. If I use normal string variables, the objects are different, so the set has 2 objects. But if I add test1 and check set.contains(test2) with my FlexiableProperty, the result is true, so I have to update the object. I don't want to check the id outside of the objects (with maybe a map and the id as key)
Here the code snippet with a set:
data class Test1(val id : Int, val name: FlexibleProperty<String>)
data class FlexibleProperty<T>(var value: T) {
override fun equals(other: Any?) = true
override fun hashCode() = 1
}
fun main() {
val test1 = Test1(1, FlexibleProperty("Hans"))
val test2 = test1.copy(name = FlexibleProperty("Dieter"))
val setTest = mutableSetOf(test1)
if (setTest.contains(test2)) {
setTest.remove(test1)
}
setTest.add(test2)
println("set $setTest")
}
There's no specific problem with your solution per see, but it could be greatly improved.
First, name can still be a value, since you use copy() anyway:
data class Test1(val id : Int, val name: FlexibleProperty<String>)
val test2 = test1.copy(name = FlexibleProperty("Dieter"))
Having no mutable properties make your class thread safe, and easier to reason about.
Second, when you use data class at the top level, it makes a lot of sense to make all classes it encapsulates also data classes. That would also solve your second problem with the need of overriding equals and hashCode:
data class FlexibleProperty<T>(var value: T)
Also, there's no reason to check referential equality with ===, at least with the examples you provide.
Let's say I have the following code:
open class Fruit
class Apple : Fruit()
open class Juice<T : Fruit>
class AppleJuice : Juice<Apple>()
fun <F : Fruit, J : Juice<F>> makeJuice(juiceClass : Class<J>, fruit : F) : J {}
I call the function like this:
val appleJuice : AppleJuice = makeJuice(AppleJuice::class.java, Apple())
But instead of passing a class object I would like to pass AppleJuice as a type:
val appleJuice : AppleJuice = makeJuice<AppleJuice>(Apple())
I have refactored my function to inline with reified:
inline fun <F : Fruit, reified J : Juice<F>> makeJuice(fruit : F) : J {}
But now I have to specify both types:
val appleJuice : AppleJuice = makeJuice<Apple, AppleJuice>(Apple())
In theory, Apple type shouldn't be needed because it's already known from AppleJuice type. Is it somehow possible to get rid of passing unnecessary types and pass only those maked as reified?
The main problem I see with your solution is, that you are asking for 2 generic types on your makeJuice-method. Both F and J need to be given to the function. While it is obvious for you (and anyone looking at the method), I think it might not be that obvious during runtime when the generic types are erased (but that is now mainly a guess here).
If you do not mind that the fruits you are passing are not really matching subtypes of the juice you are expecting then the following may be something for you:
inline fun <reified J : Juice<out Fruit>> makeJuice(fruit : Fruit) : J = TODO()
If however you want to ensure that AppleJuice can only be constructed with Apples, then I can only think of solutions similar to the following:
adding the makeJuice to the Fruit classes, e.g.
abstract class Fruit {
abstract fun makeJuice() : Juice<out Fruit>
}
// and subclasses:
class Apple : Fruit() {
override fun makeJuice(): AppleJuice = TODO()
}
adding a makeJuice (/makeFrom?) to the Juice classes, e.g.
open class Juice<T : Fruit> {
fun makeFrom(fruit : T) { TODO() }
}
adding any other intermediate object so that you do not require 2 generic types at once, e.g.
class JuiceMaker<F : Fruit>(val fruit : F) {
inline fun <reified J : Juice<F>> makeJuice() : J = TODO()
}
fun <F : Fruit> using(fruit : F) = JuiceMaker(fruit)
and calling it with
using(Apple()).makeJuice<AppleJuice>()
variants of the above using extension functions, e.g.
inline fun <reified J : Juice<out Apple>> Apple.makeJuice() : J = TODO()
but you need to specify it for all types. The following unfortunately will not work:
inline fun <F : Fruit, reified J : Juice<F>> F.makeJuice() : J = TODO()
as we then have the same problem again... and need to specify <Apple, AppleJuice>.
But maybe none of these are what you were hoping to get.
So if you want to have a single method that handles it all, the third variant is probably your best choice (even though it uses a wrapper).
I've read the docs on it 3 times and I still have no idea what it does. Can someone ELI5 (Explain Like I'm Five) it please? Here's how I'm using it:
fun main(args: Array<String>) {
val UserModel = UserModel()
val app = Javalin.create().port(7000).start()
with (app) {
get("/users") {
context -> context.json(UserModel)
}
}
}
with is used to access an object's members and methods without having to refer to the object once per access. It is (mostly) for abbreviating your code. It is frequently used when constructing an object:
// Verbose way, 204 characters:
var thing = Thingummy()
thing.component1 = something()
thing.component2 = somethingElse()
thing.component3 = constantValue
thing.component4 = foo()
thing.component5 = bar()
parent.children.add(thing)
thing.refcount = 1
// Terse way, 182 characters:
var thing = Thingummy()
with(thing) {
component1 = something()
component2 = somethingElse()
component3 = constantValue
component4 = foo()
component5 = bar()
parent.children.add(this)
refcount = 1
}
The documentation says:
inline fun <T, R> with(receiver: T, block: T.() -> R): R (source)
Calls the specified function block with the given receiver as its receiver and returns its result.
The way I think of it is that it is calling a function (the block) where this in the scope of the block is the receiver.
Whatever the block returns is the return type.
Essentially calling a method where you provide the implicit this and can return any result from it.
Here is an example to demonstrate:
val rec = "hello"
val returnedValue: Int = with(rec) {
println("$this is ${length}")
lastIndexOf("l")
}
The rec in this case is the receiver of the function call - the this in the scope of the block. The $length and lastIndexOf are both called on the receiver.
The return value can be seen to be an Int because that is the last method call in the body - that is the generic type parameter R of the signature.
The definition of with:
inline fun <T, R> with(receiver: T, block: T.() -> R): R (source)
Actually it's implementation is straight forward: The block is executed on receiver, which works for any type:
receiver.block() //that's the body of `with`
The great thing to mention here, is the parameter type T.() -> R:
It's called function literal with receiver. It's actually a lambda that can access the receiver's members without any additional qualifiers.
In your example the context of with receiver app is accessed in that way.
Besides stdlib functions like with or apply, this functionality is what makes Kotlin great for writing Domain Specific Languages as it allows the creation of scopes within which you have access on certain functionalities.
val citizen2 = Citizen("Tom", 24, "Washington")
val age = with(citizen2) {
println("$name - $age $residence ")
age = this.age + age
residence = "Florida"
age+10 // returns 58
}
println("${citizen2.name} - ${citizen2.age} - $age - ${citizen2.residence} ")
data class Citizen(var name: String, var age: Int, var residence: String)
Output:
Tom - 24 Washington
Tom - 48 - 58 - Florida
Note that :
We can access age property of citizen(receiver object) with this.age or age
last line(age+10 in this example) in the lambda of with() returns.
With is used to apply several operations to an object or access object's methods e.g. in this example we are accessing String's capitalize() extension method
data class Person(val name:String)
fun main(){
val person = Person("john doe")
with(person) {
println(name.capitalize()) // output John Doe
}
}
Under the hood with is a higher-order function. Here we are saying with the Person name call capitalize ( ). We don’t actually need ‘this’ because it is implicit and can be removed