Allow reference to variables in class declared with Any - kotlin

I have a function what take a List It can be many difference classes that contain a number of fields (open, high, low, close). The classes contain other fields. But I don't want to write one function for each class that I am going to map over. Is there a way to allow for the fields to be specified without getting "unresolved reference"
fun createTA4JBarsFromAlgobars(timebars: List<Any?>, name: String): BaseBarSeries? {
val series = BaseBarSeriesBuilder().withName(name).build()
//all it.unixSecond etc. Get unresolved reference with compiling
timebars.map { series.addBar(utilService.unixtimeToZoneDateTime(it.unixSecond), it.open, it.high, it.low, it.close, it.volume) }
return series
}

It is extremely rare to ever have a reason to have a List<Any>. (In 12 years of Java and Kotlin use, I don't recall ever doing that.) If there is some property you want to get from all the items in the list, you should have all of them inherit from a common interface that defines those properties. Then you can create a list of that interface type and put in instances of various different classes that all conform to that interface. For example:
interface TimeBar {
val unixSecond: Long
val open: Float
val close: Float
val high: Float
val low: Float
val volume: Float
}
// Make all your various classes for your list implementers of the above interface.
// Then make your list a `List<TimeBar>`.
In your case, if each class type doesn't have high, low, etc. properties, but instead they all get added to your chart in various different ways, you could instead create a common interface for adding the instance to your chart, for example:
interface TimeBar {
fun addToBaseBarSeries(series: BaseBarSeries)
}
// in each of your classes, some implementation of the above function:
override fun addToBaseBarSeries(series: BaseBarSeries) {
series.addBar(utilService.unixtimeToZoneDateTime(unixSecond), open, high, low, close, volume)
}
You are also using map improperly. It is not for creating side effects. It is for creating a new list of a different type. You should be using a for loop instead.

Related

Generic variance type parameter(Kotlin)

I do not fully understand how variance in Generics work. In the code below the classes are as follows Any -> Mammals -> Cats. Any is the supertype, there is a parameter called from in the copy function
From what I understand about the out and in keywords, out allows reference to any of it's subtype, can only be produced not consumed.
in allows reference to any of it's supertype, can only be consumed not produced.
However in the copytest function we are instantiating the function copy. I gave it a catlist1 argument in the from parameter. Since the parameter has an out keyword wouldn't it mean that we can only input parameters that are a subtype of catlist2?
To top of my confusion I have seen many conflicting definitions, for instance , In Kotlin, we can use the out keyword on the generic type which means we can assign this reference to any of its supertypes.
Now I am really confused could anybody guide me on how all of these works? Preferably from scratch, thanks!
class list2<ITEM>{
val data = mutableListOf<ITEM>()
fun get(n:Int):ITEM = data[n]
fun add(Item:ITEM){data.add(Item)}
}
fun <T> Copy(from: list2<out T>, to:list2<T>){
}
fun copytest(){
val catlist1 = list2<Cat>()
val catlist2 = list2<Cat>()
val mammallist = list2<Mammal>()
Copy(catlist1,mammallist)
}
I think maybe you're mixing up class-declaration-site generics and use-site generics.
Class-declaration-site generics
Defined at the class declaration site with covariant out, it is true you cannot use the generic type as the type of a function parameter for any functions in the class.
class MyList<out T>(
private val items: Array<T>
) {
fun pullRandomItem(): T { // allowed
return items.random()
}
fun addItem(item: T) { // Not allowed by compiler!
// ...
}
}
// Reason:
val cowList = MyList<Cow>(arrayOf(Cow()))
// The declaration site out covariance allows us to up-cast to a more general type.
// It makes logical sense, any cow you pull out of the original list qualifies as an animal.
val animalList: MyList<Animal> = cowList
// If it let us put an item in, though:
animalList.addItem(Horse())
// Now there's a horse in the cow list. That doesn't make logical sense
cowList.pullRandomItem() // Might return a Horse, impossible!
It is not logical to say, "I'm going to put a horse in a list that may have the requirement that all items retrieved from it must be cows."
Use-site generics
This has nothing to do with the class level restriction. It's only describing what kind of input the function gets. It is perfectly logical to say, "my function does something with a container that I'm going to pull something out of".
// Given a class with no declaration-site covariance of contravariance:
class Bag<T: Any>(var contents: T?)
// This function will take any bag of food as a parameter. Inside the function, it will
// only get things out of the bag. It won't put things in it. This makes it possible
// to pass a Bag of Chips or a Bag of Pretzels
fun eatBagContents(bagOfAnything: Bag<out Food>) {
eat(bagOfAnything.contents) // we know the contents are food so this is OK
bagOfAnything.contents = myChips // Not allowed! we don't know what kind of stuff
// this bag is permitted to contain
}
// If we didn't define the function with "out"
fun eatBagContentsAndPutInSomething(bagOfAnything: Bag<Food>) {
eat(bagOfAnything.contents) // this is fine, we know it's food
bagOfAnything.contents = myChips // this is fine, the bag can hold any kind of Food
}
// but now you cannot do this
val myBagOfPretzels: Bag<Pretzels> = Bag(somePretzels)
eatBagContentsAndPutInSomething(myBagOfPretzels) // Not allowed! This function would
// try to put chips in this pretzels-only bag.
Combining both
What could be confusing to you is if you saw an example that combines both of the above. You can have a class where T is a declaration site type, but the class has functions where there are input parameters where T is part of the definition of what parameters the function can take. For example:
abstract class ComplicatedCopier<T> {
abstract fun createCopy(item: T): T
fun createCopiesFromBagToAnother(copyFrom: Bag<out T>, copyTo: Bag<in T>) {
val originalItem = copyFrom.contents
val copiedItem = createCopy(originalItem)
copyTo.contents = copiedItem
}
}
This logically makes sense since the class generic type has no variance restriction at the declaration site. This function has one bag that it's allowed to take items out of, and one bag that it's allowed to put items into. These in and out keywords make it more permissive of what types of bags you can pass to it, but it limits what you're allowed to do with each of those bags inside the function.

Why is my kotlin hash set not adding elements

I am new to kotlin and I want to make an abstract/open class or interface, something that can be implemented by other classes. Let's call it Test. Now Test needs to have a HashSet (the docs say it requires less memory than a normal set) that every derived class will implement and fill with its own values.
interface Test {
val players: HashSet<String>
}
class Supa: Test {
override val players = hashSetOf<String>()
fun later() {
players.add("new player")
}
}
fun main() {
Supa().later()
println(Supa().players)
}
The above will output []. It seems that for some reason players doesn't get updated. After playing around in the kotlin playground I found out that if I print players from inside later() it will show the added element. Maybe it creates a new instance of player that exists in the scope of the function?? Could someone please show me how I can make an abstract hashSet that the derived class can override and fill with values that stay in the set?
The problem here is that you create two separate instances of Supa. You invoke later() on one of them and then print players of another one. Each Supa() creates a new instance.
You need to store Supa instance inside a variable and use it in both places:
val supa = Supa()
supa.later()
println(supa.players)
This isn't really specific to Kotlin. Your code would work the same in other languages as well.

Multiple types of a class within a class

I'm making a simple game to learn some kotlin, and I'm a little confused on the best way to change this around using OOP.
I have a class for backpack setup so that it has another class called items that will be different types of items. Below I've recreated a simple version of what I have.
class backPack {
private val item: Item
init { item = Item() }
fun display() {
item.display()
}
}
class Item {
fun display() { println("Your item!") }
}
fun main() {
val examplePack = backPack()
examplePack.display()
}
I want to change the backPack class to allow for different types of items. For example, health potions and mana potions. I considered making the item an open class, then having something like this:
class healthPotion : Item() {
override fun display() {
println("health potion!")
}
}
class manaPotion : Item() {
override fun display() {
println("mana potion!")
}
}
which seems correct, but I'm a little stuck on how to refactor the backpack class to allow different types of items and I want to make sure this seems like a proper way to do this. Any assistance is very appreciated, thank you!
That's basically the idea! If your BackPack class (it should start with a capital by convention) handles Items, then any class that has that type will work. You have two options - inheritance, and composition.
Inheritance is where you build a hierarchy of classes, e.g.:
open class Item {
val weight: Int
fun Describe()
}
open class Potion : Item() {
fun drink() {}
}
// this is a Potion, and a Potion is an Item, meaning this is an Item
class ManaPotion : Potion() {
override fun drink() {
println("whoa!")
}
}
// etc
The problem there is you're locked into a rigid hierarchy - what if you had a StaleBread that's a Food, but you also want it to be a Weapon? You can use interfaces to compose your object by giving it multiple types, not just a parent:
open class Item
interface Food {
fun eat() {
println("yum")
}
}
interface Weapon {
fun attack() {
println("RARGH")
}
}
class StaleBread : Item(), Food, Weapon
Because StaleBread has all of those types, you can treat it as any of them, because it is all of them. Because it's a Weapon, it's guaranteed to have an attack() method, etc. You can add it to a List<Food>, because it is a Food. Being able to treat objects as different types is called polymorphism. So you're able to compose an object from different types, to give it certain properties, certain behaviours, etc
Your example should work as-is because you're handling Items in your backpack, and your two potion classes are both Items (descendants of that class, specifically, since you're inheriting from the Item class). There are lots of ways to organise it - if you get into some tutorials about inheritance, composition and polymorphism (this is only a simple overview that skips over a bunch of things) you'll start to get some ideas about how to move forward
oh yeah, for the actual backpack, you probably want something like this:
class BackPack {
private val items = mutableListOf<Item>()
fun addItem(item: Item) {
// here you could do things like check it doesn't exceed the allowed weight
// or capacity of the backpack
items.add(item)
}
}
This way, your backpack can contain multiple Items, and you can control how those are accessed through the class's functions and properties. Anything which is an Item type can go in there!
If you want to be able to change which item is in the bag, the property should be a var. If you want the bag to be able to be empty, then it should be a nullable property (declared with a ? after the type so it can hold null).
By the way, class names should always start with a capital letter so your code will be easier to read. And you can initialize properties at the declaration site instead of using a separate init block.
class Backpack {
var item: Item? = null
fun display() {
item?.display()
}
}
Your generic Item() doesn't seem like it would be useful in practice. Therefore, Item should probably be either an abstract class or an interface. A general OOP principle is that you should avoid deep class hierarchies. If your superclass doesn't contain logic that must be shared by all its children, it should probably be an interface instead.

Creating the analogue of BigInteger.ZERO for own data type in Kotlin

So, as is well-known, Kotlin is able to access Java libraries, and among them is the BigInteger class. And this class has a very handy feature: There is a keyword, called "BigInteger.ZERO", which returns a BigInteger object whose value equals zero.
Now I am writing a fraction data type, and I'd very much like to do the same thing for it. But the problem with just putting a val inside the class is that this first needs an object to begin with; it's not a "static" constant, so to say.
I'd be very grateful indeed for any forthcoming replies.
You can put the constant as a val inside the companion object of your class:
class Fraction {
...
companion object {
val ZERO = Fraction()
}
}
Then you can call your constant by Fraction.ZERO.
Note that this only makes sense if your fraction class is immutable.

Kotlin Interface method abstraction

I'm exploring the Substitution principal and from what I've understood about the principal is that a sub type of any super type should be passable into a function/class. Using this idea in a new section of code that I'm writing, I wanted to implement a abstract interface for a Filter like so
interface Filter {
fun filter(): Boolean
}
I would then imagine that this creates the contract for all classes that inherit this interface that they must implement the function filter and return a boolean output. Now my interpretation of this is that the input doesn't need to be specified. I would like it that way as I want a filter interface that guarantee the implementation of a filter method with a guarantee of a return type boolean. Does this concept even exists in Kotlin? I would then expect to implement this interface like so
class LocationFilter {
companion object : Filter {
override fun filter(coord1: Coordinate, coord2: Coordinate): Boolean {
TODO("Some business logic here")
}
}
}
But in reality this doesn't work. I could remove remove the filter method from the interface but that just defeats the point of the whole exercise. I have tried using varargs but again that's not resolving the issue as each override must implement varargs which is just not helpful. I know this may seem redundant, but is there a possibility to have the type of abstraction that I'm asking for? Or am I missing a point of an Interface?
Let's think about it a little. The main point of abstraction is that we can use Filter no matter what is the implementation. We don't need to know implementations, we only need to know interfaces. But how could we use Filter if we don't know what data has to be provided to filter? We would need to use LocationFilter directly which also defeats the point of creating an interface.
Your problem isn't really related to Kotlin, but to OOP in general. In most languages it is solved by generics/templates/parameterized types. It means that an interface/class is parameterized by another type. You use it in Kotlin like this:
interface Filter<in T> {
fun filter(value: T): Boolean
}
object LocationFilter : Filter<Coordinate> {
override fun filter(value: Coordinate): Boolean {
TODO()
}
}
fun acquireCoordinateFilter(): Filter<Coordinate> = LocationFilter
fun main() {
val coord: Coordinate = TODO()
val filter: Filter<Coordinate> = acquireCoordinateFilter()
val result = filter.filter(coord)
}
Filter is parameterized, meaning that we can have a filter for filtering strings (type is: Filter<String>), for filtering integers (Filter<Int>) or for filtering coordinates (Filter<Coordinate>). Then we can't use e.g. Filter<String> to filter integers.
Note that the code in main() does not use LocationFilter directly, it only knows how to acquire Filter<Coordinate>, but the specific implementation is abstracted from it.
Also note there is already a very similar interface in Java stdlib. It is called Predicate.
my interpretation of this is that the input doesn't need to be specified.
Where did you get that interpretation from?
You can see that it can't be correct, by looking at how the method would be called.  You should be able to write code that works for any instance of Filter — and that can only happen if the number and type of argument(s) is specified in the interface.  To use your example:
val f: Filter = someMethodReturningAFilterInstance()
val result = f.filter(coord1, coord2)
could only work if all implementations used two Coordinate parameters. If some used one String param, and others used nothing at all, then how would you call it safely?
There are a few workarounds you could use.
If every implementation takes the same number of parameters, then you could make the interface generic, with type parameter(s), e.g.:
interface Filter<T1, T2> {
fun filter(t1: T1, t2: T2): Boolean
}
Then it's up to the implementation to specify which types are needed.  However, the calling code either needs to know the types of the particular implementation, or needs to be generic itself, or the interface needs to provide type bounds with in variance.
Or if you need a variable number of parameters, you could bundle them up into a single object and pass that.  However, you'd probably need an interface for that type, in order to handle the different numbers and types of parameters, and/or make that type a type parameter on Filter — all of which smells pretty bad.
Ultimately, I suspect you need to think about how your interface is going to be used, and in particular how its method is going to be called.  If you're only ever going to call it when the caller knows the implementation type, then there's probably no point trying to specify that method in the interface (and maybe no point having the interface at all).  Or if you'll want to handle Filter instances without knowing their concrete type, then look at how you'll want to make those calls.
The whole this is wrong!
First, OOP is a declarative concept, but in your example the type Filter is just a procedure wrapped in an object. And this is completely wrong.
Why do you need this type Filter? I assume you need to get a collection filtered, so why not create a new object that accepts an existing collection and represents it filtered.
class Filtered<T>(private val origin: Iterable<T>) : Iterable<T> {
override fun iterator(): Iterator<T> {
TODO("Filter the original iterable and return it")
}
}
Then in your code, anywhere you can pass an Iterable and you want it to be filtered, you simply wrap this original iterable (any List, Array or Collection) with the class Filtered like so
acceptCollection(Filtered(listOf(1, 2, 3, 4)))
You can also pass a second argument into the Filtered and call it, for example, predicate, which is a lambda that accepts an element of the iterable and returns Boolean.
class Filtered<T>(private val origin: Iterable<T>, private val predicate: (T) -> Boolean) : Iterable<T> {
override fun iterator(): Iterator<T> {
TODO("Filter the original iterable and return it")
}
}
Then use it like:
val oddOnly = Filtered(
listOf(1, 2, 3, 4),
{ it % 2 == 1 }
)