Aim of the code: Class Pair can print out Product name and quantity, Product name stored in Class Product
class Pair<T, U>(var product: Product, var quantity: Int) {
for ( (product,quantity) in productAndQuantityList) {
println("Name: ${product.productName}")
println("Quantity: $quantity")
}
}
Above Error:(2, 9) Kotlin: Expecting member declaration
Error:(2, 57) Kotlin: Function declaration must have a name
class ShoppingCart{
private val productAndQuantityList = mutableListOf<Pair<Product,Int> >()
...
}
open class Product(
val productName: String,
var basePrice: Double,
open val salesPrice: Double,
val description: String) {
...}
may i know how to change my code?
after class Pair was suggested by Compiler, but should i fill in anything?
Which topic should i work for, to avoid the same errors again?
Thanks!
If you want to run the for loop when the object is instantiated, then you should use an initializer. You can't simply put statements inside class definitions directly.
class Pair<T, U>(var product: Product, var quantity: Int) {
init {
for ( (product,quantity) in productAndQuantityList) {
println("Name: ${product.productName}")
println("Quantity: $quantity")
}
}
}
However, this code is wrong because Pair does not have access to productAndQuantityList, although ShoppingCart does. As Mathias Henze suggested, you should make a function in ShoppingCart and move the for loop into that, like this:
fun printProducts() {
for ( (product,quantity) in productAndQuantityList) {
println("Name: ${product.productName}")
println("Quantity: $quantity")
}
}
As for your Pair class, the type parameters T and U are unnecessary, as you don't use them anywhere, and the class itself is provided by the standard library (The header looks something like data class Pair<out A, out B>(val first: A, val second: B).
If you're determined to use your own Pair class, be sure to make it a data class, so it can be destructured, and change the type of productAndQuantityList to mutableListOf<Pair> (without the type parameters Pair<Product, Int>).
Update
Please read the answer by Mathias Henze, which is correct. My answer, was originally completely wrong, but I have now corrected it.
The productAndQuantityList is just for storing the data. The Pair class is a provided class by Kotlin. You don't need to add anything to it in your usecase.
The ability to print the product and the quantity should be a function of the ShoppingCart, so just have:
class ShoppingCart{
private val productAndQuantityList = mutableListOf<Pair<Product,Int> >()
// ...
fun printContents() {
for ( (product,quantity) in productAndQuantityList) {
println("Name: ${product.productName}")
println("Quantity: $quantity")
}
}
}
Related
Let's say I have the following class constructor:
class Car(val brand: Brand,val modelName: String, val version: Int){}
If for example, I want the version number to always start with 1. Is there a way to manipulate it in the class body to achieve this ?
Meaning:
val firstdigit:Int = abs(version).ToString().Substring(0,1)
And then parse it to Int. But how to replace the original first digit after that?
I'm just learning Kotlin and I got a bit stuck with this
Is this what you had in mind?
class Car(val brand: Brand, val modelName: String) {
val version = getNextVersion()
companion object {
private var nextVersion = 0
private fun getNextVersion(): Int {
nextVersion++
if (nextVersion.toString()[0] != '1') {
nextVersion = (10.0.pow(ceil(log10(nextVersion.toDouble())))).toInt()
}
return nextVersion
}
}
}
You already said in the comments that you want the number to increment per instance, so the caller shouldn't be providing that number in the first place really! But just generally, here's two approaches to sanitising your input parameters:
1) Make it the caller's responsibility to provide valid data
init {
require(version.toString().first() == '1') { "Needs to start with 1 thanks" }
}
require throws an IllegalArgumentException if it fails, which is the standard exception for "the value of this argument is invalid". Should the class be responsible for taking bad data and trying to "fix" it, or should the caller be handling that - and maybe not constructing an instance at all if it doesn't have valid data?
2. create a newInstance function that uses valid data, and keep the constructor private
class Thing private constructor(val number: Int){
companion object {
fun newInstance(num: Int): Thing {
return Thing(abs(num))
}
}
}
fun main() {
Thing.newInstance(-2).let { println(it.number)}
}
If it makes sense for the class itself to sanitise the input parameters, you can delegate construction to a function that takes care of that, and prevent things from calling the constructor directly with potentially bad data.
This can cause issues with e.g. serialisation libraries (which want to call the constructor directly) but in that case you could leave the constructor public, and just advise callers to call newInstance instead. Not ideal, but it's an option!
I came across something and wondered all the time why you should do this.
You implement an interface in Kotlin through a simple function type:
"It is possible for a class to implement a function type as if it were an interface. It must then supply an operator function called invoke with the given signature, and instances of that class may then be assigned to a variable of that function type:"
class Divider : (Int, Int) -> Double {
override fun invoke(numerator: Int, denominator: Int): Double = ...
}
But why should I do this? Why should I add an interface in that way? I think its only possible to add one function and not more.
Or is it an advantage that I can implement a function with a function body and not only the function head like in normal interfaces? I think it is possible in Java to add default methods to interfaces with a function body. So maybe it is something like that?
Function as a class can have state. For example you could store the last invocations and use the history as a cache:
class Divider : (Int, Int) -> Double {
val history = mutableMapOf<Pair<Int, Int>, Double>()
override fun invoke(numerator: Int, denominator: Int): Double {
return history.computeIfAbsent(Pair(numerator, denominator)) {
numerator.toDouble() / denominator.toDouble()
}
}
}
fun main() {
val divider = Divider()
println(divider(1,2))
println(divider(2,3))
println(divider.history)
}
It is probably not very useful to write a class that only implements a function type interface; however, it might be useful to write a class that can among other things be used in place of a function.
An example from the standard library is the KProperty1 interface. You can write code like this:
data class C(val id: Int, val name: String)
val objs = listOf(C(1, "name1"), C(2, "name2"), C(3, "name3"))
val ids = objs.map(C::id)
Here, C::id is a property reference of type KProperty1<C, Int>, and it can be used as an argument to List.map in place of a lambda because KProperty1<C, Int> extends (C) -> Int. However, KProperty1 has a lot of other uses besides being passed as a function.
I have two library classes, Item and ItemFood : Item (that is derived from Item), and a library function registerItem(item: Item, name: String). I cannot modify them.
I have two of my own classes (ItemKey : Item and ItemBerry : ItemFood) that are derived from the library classes.
What I want is to store the name: String property in my classes ItemKey and ItemBerry and make them "count" as a NamedItem, so I can write a function like so:
fun registerNamedItem(namedItem: NamedItem) {
registerItem(namedItem, namedItem.name)
}
I cannot just make a class like so: class NamedItem(val name: String) : Item and derive my classes from it, because sometimes I need to derive my classes from ItemFood, not from Item.
I don't want to make a class wrapper like class NamedItem(val item: Item, val name: String), because then every time I want to get the "underlying" Item I will need to manually get the item property: registerItem(namedItem.item, namedItem.name), and this is ugly.
I cannot use an interface INamedItem { val name: String } and implement this interface in ItemKey and ItemBerry, because then I will need to write a function in this way:
fun registerNamedItem(item: Item, namedItem: INamedItem) {
registerItem(item, namedItem.name)
}
, and it is not an improvement at all.
Is there some kind of advanced technique - using an interface, delegation, generic, whatever - so I can implement the registerNamedItem function like I want it - passing to the registerItem(item: Item, name: String) an instance of the NamedItem as the first parameter and the namedItem.name as the second parameter?
Actually, you could use interface just for that:
fun main() {
registerNamedItem(ItemKey("item_key"))
registerNamedItem(ItemBerry("item_berry"))
}
// Cannot change this
open class Item
// Cannot change this
open class ItemFood : Item()
// This is your class
class ItemKey(override val name: String) : NamedItem()
// This is also your class
class ItemBerry(override val name: String) : NamedFoodItem()
// This is the property you would like to enforce
interface INamedItem {
val name: String
}
// Since Item and ItemFood are concrete classes, you don't have much choice there
abstract class NamedItem : Item(), INamedItem
abstract class NamedFoodItem : ItemFood(), INamedItem
// Adapter pattern
fun registerNamedItem(namedItem: NamedFoodItem) {
registerItem(namedItem, namedItem.name)
}
// Adapter pattern
fun registerNamedItem(namedItem: NamedItem) {
registerItem(namedItem, namedItem.name)
}
fun registerItem(namedItem: Item, name: String) {
println("Item $namedItem registered with $name")
}
Delegation won't work in your case, since from your example, Item is a class, and you can only delegate to interfaces.
In a method I would like to receive KMutableProperty as parameter and assign a value to it.
Another question is what is the correct way of passing a parameter into such a method.
Basically I would like to have something like that:
class MyBinder {
...
fun bind(property: KMutableProperty<Int>): Unit {
property.set(internalIntValue)
}
}
And then call it in another class
myBinder.bind(this::intProperty)
Kotlin 1.0 does not allow the this::intProperty syntax, but this is being worked currently and will be available soon as a part of the early access preview of 1.1 (issue, KEEP proposal).
With this in mind, I'd consider doing what you're describing in another way, for example making bind accept a lambda which sets the property:
class MyBinder {
fun bind(setProperty: (Int) -> Unit) {
setProperty(internalIntValue)
}
}
...
myBinder.bind { intProperty = it }
Anyway, to answer your question about setting the value of KMutableProperty: to set the value of some property or, technically speaking, to invoke the property setter, you should know its arity, or the number of parameters that property (and its getter/setter) accepts. Properties declared in a file do not accept any parameters, member properties and extension properties require one parameter (the receiver instance), while member properties which are also extensions take two parameters. These kinds of properties are represented by the following subtypes of KMutableProperty respectively: KMutableProperty0, KMutableProperty1, KMutableProperty2 -- the number means the arity and their generic type parameters mean the types of receivers. Each of these property types has a set method with the corresponding parameters. Some examples:
fun setValue(property: KMutableProperty0<Int>, value: Int) {
property.set(value)
}
fun setValue(property: KMutableProperty1<SomeType, Int>, instance: SomeType, value: Int) {
property.set(instance, value)
}
Note that there's no set (or get) method in the abstract KMutableProperty interface precisely because it's impossible to declare it, not knowing the number of required receiver parameters.
Additionally to Alexander's answer, you can try something like this:
import kotlin.reflect.KMutableProperty
class Binder {
val internalIntValue = 10
fun bind(self: Any, aProperty: KMutableProperty<Int>) {
aProperty.setter.call(self, internalIntValue)
}
}
class Foo {
var bar = 1
fun changeBar() {
Binder().bind(this, Foo::bar)
}
}
fun main(args: Array<String>) {
val foo = Foo()
assert(1 == foo.bar)
foo.changeBar()
assert(10 == foo.bar)
}
A more robust/safe way to do the same thing:
fun <T> bind(self: T, aProperty: KMutableProperty1<T, Int>) {
aProperty.set(self, internalIntValue)
}
My thanks to Alexander. His answer gave me the previous idea.
Does Kotlin have anything like discriminated unions (sum types)? What would be the idiomatic Kotlin translation of this (F#):
type OrderMessage =
| New of Id: int * Quantity: int
| Cancel of Id: int
let handleMessage msg =
match msg with
| New(id, qty) -> handleNew id qty
| Cancel(id) -> handleCxl id
Kotlin's sealed class approach to that problem is extremely similar to the Scala sealed class and sealed trait.
Example (taken from the linked Kotlin article):
sealed class Expr {
class Const(val number: Double) : Expr()
class Sum(val e1: Expr, val e2: Expr) : Expr()
object NotANumber : Expr()
}
The common way of implementing this kind of abstraction in an OO-language (e.g. Kotlin or Scala) would be to through inheritance:
open class OrderMessage private () { // private constructor to prevent creating more subclasses outside
class New(val id: Int, val quantity: Int) : OrderMessage()
class Cancel(val id: Int) : OrderMessage()
}
You can push the common part to the superclass, if you like:
open class OrderMessage private (val id: Int) { // private constructor to prevent creating more subclasses outside
class New(id: Int, val quantity: Int) : OrderMessage(id)
class Cancel(id: Int) : OrderMessage(id)
}
The type checker doesn't know that such a hierarchy is closed, so when you do a case-like match (when-expression) on it, it will complain that it is not exhaustive, but this will be fixed soon.
Update: while Kotlin does not support pattern matching, you can use when-expressions as smart casts to get almost the same behavior:
when (message) {
is New -> println("new $id: $quantity")
is Cancel -> println("cancel $id")
}
See more about smart casts here.
The sealed class in Kotlin has been designed to be able to represent sum types, as it happens with the sealed trait in Scala.
Example:
sealed class OrderStatus {
object Approved: OrderStatus()
class Rejected(val reason: String): OrderStatus()
}
The key benefit of using sealed classes comes into play when you use them in a when expression for the match.
If it's possible to verify that the statement covers all cases, you don't need to add an else clause to the statement.
private fun getOrderNotification(orderStatus:OrderStatus): String{
return when(orderStatus) {
is OrderStatus.Approved -> "The order has been approved"
is OrderStatus.Rejected -> "The order has been rejected. Reason:" + orderStatus.reason
}
}
There are several things to keep in mind:
In Kotlin when performing smartcast, which means that in this example it is not necessary to perform the conversion from OrderStatus to OrderStatus.Rejected to access the reason property.
If we had not defined what to do for the rejected case, the compilation would fail and in the IDE a warning like this appears:
'when' expression must be exhaustive, add necessary 'is Rejected' branch or 'else' branch instead.
when it can be used as an expression or as a statement. If it is used as an expression, the value of the satisfied branch becomes the value of the general expression. If used as a statement, the values of the individual branches are ignored. This means that the compilation error in case of missing a branch only occurs when it is used as an expression, using the result.
This is a link to my blog (spanish), where I have a more complete article about ADT with kotlin examples: http://xurxodev.com/tipos-de-datos-algebraicos/
One would be doing something like this:
sealed class Either<out A, out B>
class L<A>(val value: A) : Either<A, Nothing>()
class R<B>(val value: B) : Either<Nothing, B>()
fun main() {
val x = if (condition()) {
L(0)
} else {
R("")
}
use(x)
}
fun use(x: Either<Int, String>) = when (x) {
is L -> println("It's a number: ${x.value}")
is R -> println("It's a string: ${x.value}")
}