Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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)
}
}

}
2 changes: 1 addition & 1 deletion core-kotlin-modules/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
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>
<groupId>com.baeldung</groupId>
<artifactId>core-kotlin-modules</artifactId>
<packaging>pom</packaging>

Expand All @@ -26,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