Skip to content

Commit

Permalink
KTLN-622: Implement code for the article differentiating Kotlin Any v…
Browse files Browse the repository at this point in the history
…s * in generics. (#1142)

* KTLN-622: Implement code for the article differentiating Kotlin Any vs * in generics.

* KTLN-622: Implement code for the article differentiating Kotlin Any vs * in generics.

* KTLN-622: Implement code for the article differentiating Kotlin Any vs * in generics.

* KTLN-622: Implement code for the article differentiating Kotlin Any vs * in generics.

* KTLN-622: Implement code for the article differentiating Kotlin Any vs * in generics.
  • Loading branch information
vedarths authored Dec 30, 2024
1 parent 0691d79 commit 35f7d4f
Show file tree
Hide file tree
Showing 8 changed files with 156 additions and 1 deletion.
2 changes: 1 addition & 1 deletion core-kotlin-modules/core-kotlin-11/README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
### Relevant Articles
- [Convert a Data Class to ByteBuffer in Kotlin](https://www.baeldung.com/kotlin/convert-data-class-to-bytebuffer)

2 changes: 2 additions & 0 deletions core-kotlin-modules/core-kotlin-12/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
### Relevant Articles
- Difference between "*" and "Any" in Kotlin generics - Link to be updated
37 changes: 37 additions & 0 deletions core-kotlin-modules/core-kotlin-12/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>core-kotlin-12</artifactId>
<name>core-kotlin-12</name>
<packaging>jar</packaging>

<parent>
<groupId>com.baeldung</groupId>
<artifactId>core-kotlin-modules</artifactId>
<version>1.0.0-SNAPSHOT</version>
</parent>

<build>
<sourceDirectory>src/main/kotlin</sourceDirectory>
<testSourceDirectory>src/test/kotlin</testSourceDirectory>
<plugins>
<plugin>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-plugin</artifactId>
<version>${kotlin.version}</version>
<executions>
<execution>
<id>compile</id>
<phase>compile</phase>
<goals>
<goal>compile</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.baeldung.casting

sealed class Candy(val name: String) {
override fun toString() = name
}

object ChocolateBar: Candy("Chocolate Bar")
object Lollipop : Candy("Lollipop")
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.baeldung.casting

sealed class SpookyTrinket(val name: String) {
override fun toString() = name
}
object FakeSpider : SpookyTrinket("Fake Spider")
object VampireFang : SpookyTrinket("Vampire Fang")
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package com.baeldung.casting

import kotlin.collections.MutableList
import kotlin.collections.mutableListOf
import kotlin.collections.firstOrNull

class TreatDispenser<T>(private val treats: MutableList<T> = mutableListOf()) {

// Dispense the first treat
fun dispenseTreat(): T? {
return if (treats.isNotEmpty()) treats.removeFirst() else null
}

// Peek at the next treat without removing it
fun peekNextTreat(): T? {
return treats.firstOrNull()
}

// Add a treat to the dispenser
fun addTreat(treat: T) {
treats.add(treat)
}
}

// Function using * (Star Projection)
fun peekAtNextTreat(dispenser: TreatDispenser<*>) {
val nextTreat = dispenser.peekNextTreat()
println("The next treat is: $nextTreat")
}

// Function using Any (restricted to non-nullable types)
fun peekAtNextTreatAny(dispenser: TreatDispenser<Any>) {
val nextTreat = dispenser.peekNextTreat()
println("The next treat is: $nextTreat")
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package com.baeldung.casting

import org.junit.Test
import org.junit.jupiter.api.Assertions.*

class TreatDispenserUnitTest {

@Test
fun `dispenseTreat should return the first treat`() {

val dispenser = TreatDispenser<Candy>()
dispenser.addTreat(ChocolateBar)
dispenser.addTreat(Lollipop)

assertEquals(ChocolateBar, dispenser.dispenseTreat())
assertEquals(Lollipop, dispenser.dispenseTreat())
assertNull(dispenser.dispenseTreat())
}

@Test
fun `peekNextTreat should show the next treat without removing it`() {
val dispenser = TreatDispenser<Candy>()
dispenser.addTreat(Lollipop)

assertEquals(Lollipop, dispenser.peekNextTreat())
assertEquals(Lollipop, dispenser.peekNextTreat())
}

@Test
fun `peekAtNextTreat using star projection works for all types`() {
val candyDispenser = TreatDispenser<Candy>()
candyDispenser.addTreat(ChocolateBar)

val trinketDispenser = TreatDispenser<SpookyTrinket>()
trinketDispenser.addTreat(VampireFang)
trinketDispenser.addTreat(FakeSpider)

// Test with Candy dispenser
assertDoesNotThrow {
peekAtNextTreat(candyDispenser)
}

// Test with Trinket dispenser
assertDoesNotThrow {
peekAtNextTreat(trinketDispenser)
}
}

@Test
fun `peekAtNextTreatAny fails for non-Any dispensers`() {
val candyDispenser = TreatDispenser<Candy>()
candyDispenser.addTreat(ChocolateBar)

// This would fail type checking, hence commented:
// peekAtNextTreatAny(candyDispenser) // Error: Type mismatch

val anyDispenser = TreatDispenser<Any>()
anyDispenser.addTreat("Surprise Treat")

assertDoesNotThrow {
peekAtNextTreatAny(anyDispenser)
}
}

}
1 change: 1 addition & 0 deletions core-kotlin-modules/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
<module>core-kotlin-9</module>
<module>core-kotlin-10</module>
<module>core-kotlin-11</module>
<module>core-kotlin-12</module>
<module>core-kotlin-advanced</module>
<module>core-kotlin-advanced-2</module>
<module>core-kotlin-advanced-3</module>
Expand Down

0 comments on commit 35f7d4f

Please sign in to comment.