Skip to content

Instantly share code, notes, and snippets.

@JorgeCastilloPrz
Created April 10, 2019 13:34
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save JorgeCastilloPrz/eaaedfcc5a02bb2a38c2120a903f9ca9 to your computer and use it in GitHub Desktop.
Save JorgeCastilloPrz/eaaedfcc5a02bb2a38c2120a903f9ca9 to your computer and use it in GitHub Desktop.
Keep87Sample project
package com.data.instances
import com.data.Repository
import com.domain.Group
import com.domain.User
extension class GroupRepository(with val userRepository: Repository<User>) : Repository<Group> {
override fun loadAll(): List<Group> {
return listOf(Group(userRepository.loadAll()))
}
override fun loadById(id: Int): Group? {
return Group(userRepository.loadAll())
}
}
package net.consumer
import com.data.Repository
import com.domain.Group
import com.domain.User
import com.validation.Validator
fun <A> validate(a: A, with validator: Validator<A>): Boolean = a.isValid()
fun <A> retrieveIfValid(id: Int, with repository: Repository<A>, with validator: Validator<A>): A? {
val x = loadById(id)
if (x == null) return null
return if (validate(x)) x else null
}
fun program(): String {
val user = retrieveIfValid<User>(25)
if (user != User(25, "Bob")) {
return "fail 1"
}
val group = retrieveIfValid<Group>(1)
return if (group == Group(listOf(User(25, "Bob")))) {
"OK"
} else {
"fail 2"
}
}
fun main(args: Array<String>) {
/**
* Resolution order for extensions is (in this strict order):
*
* - 1) Scope of the caller function.
* - 2) Companion object for the type (User).
* - 3) Companion object for the contract interface we're looking for (Repository, Validator).
* - 4) Subpackages of the type to resolve (User).
* - 5) Subpackages of the contract interface (Repository, Validator).
*
* This program has the following requirements to run (constraints):
* - An extension for Repository<User>, provided in com.data.instances.UserRepository (subpackages of the contract interface, Repository (5)).
* - An extension for Repository<Group>, provided in com.data.instances.GroupRepository (subpackages of the contract interface, Repository (5)).
* - An extension for Validator<User>, provided in com.domain.User Companion (companion object for the type (2)).
* - An extension for Validator<Group>, provided in com.validation.Validator Companion (companion object for the contract interface (3)).
*
* All of them are fulfilled, so the program completes successfully.
*/
println(program()) // successful!
/**
* Now, try to remove any of the provided extensions from any of the required places, you'll see compile time detailed errors about extensions
* not able to resolve. You'll get errors inlined (underline + IDE inspections) and when you hit compile button / run any compile commands.
*/
}
package com.data
interface Repository<A> {
fun loadAll(): List<A>
fun loadById(id: Int): A?
}
package com.domain
import com.validation.Validator
data class User(val id: Int, val name: String) {
companion object {
extension class UserValidator(): Validator<User> {
override fun User.isValid(): Boolean {
return id > 0 && name.length > 0
}
}
}
}
data class Group(val users: List<User>)
package com.data.instances
import com.data.Repository
import com.domain.User
extension object UserRepository: Repository<User> {
override fun loadAll(): List<User> {
return listOf(User(25, "Bob"))
}
override fun loadById(id: Int): User? {
return if (id == 25) {
User(25, "Bob")
} else {
null
}
}
}
package com.validation
import com.domain.Group
import com.domain.User
interface Validator<A> {
fun A.isValid(): Boolean
companion object {
extension class GroupValidator<A>(with val userValidator: Validator<User>) : Validator<Group> {
override fun Group.isValid(): Boolean {
for (x in users) {
if (!x.isValid()) return false
}
return true
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment