A type-safe implementation for collections that cannot be empty. Life is too short for emptiness-checks!

Overview

NonEmptyCollections

Making the world a little more type-safe 🌍 🏆

Cover Image

Reduce the need for emptiness checks and reduce unsafe APIs with NonEmptyCollections.

You can use NonEmptyList, NonEmptySet and NonEmptyMap to restrict the input of functions to make your code safer and avoid unnecessary runtime exceptions.

For a detailed explanation see our related article Non-Empty Lists in Kotlin.

This is an early version and work in progress. Do not hesitate to give feedback, ideas or improvements via an issue.

Examples

Average without exceptions

With the NonEmptyList type, we can make sure that at least one element is always a list. If we want to calculate the average of that list, it is impossible to compile a program where an invalid input is passed to our function.

fun NonEmptyList
   .
   average() 
   = sum() 
   / size
  
nonEmptyListOf<Int>().average()   // This does not compile! ❌

nonEmptyListOf(1, 2, 3).average() // This does! ✅

Non-empty Shopping-Cart

Let's imagine an online shop, where you can put articles into a shopping cart. If you have some articles in the shopping cart, you should be able to share the articles with your friends, save them for later on a wish list or directly buy them. But these three features just make sense if the shopping cart is not empty. Wouldn't it be cool to already prevent at compile-time that somebody tries these features with an empty set of articles?

sealed class ShoppingCart {
    object Empty : ShoppingCart()

    data class Filled(
        val articles: NonEmptySet<Article>
    ) : ShoppingCart() {

        fun buy(paymentType: PaymentType) = articles.buy(paymentType)
        fun share() = articles.share()
        fun saveTo(wishList: WishList) = articles.saveTo(wishList)
    }
}

fun NonEmptyCollection
  
.buy(paymentType: PaymentType) { 💸 } fun NonEmptyCollection
.share() { 💬 } fun NonEmptyCollection
.saveTo(wishList: WishList) { 💾 }

The devs, who implement buy, share and saveTo don't have to handle the empty case. The consumers of these APIs don't have to think of exception handling, because they are forced by the compiler to provide a valid input. We would say, that's a win-win situation 🏆 .

🏃 Library Setup

1. Add the repository

build.gradle.kts

allprojects {
    repositories {
        ...
        maven { url = uri("https://jitpack.io") }
    }
}

2. Add the dependency

build.gradle.kts

dependencies {
    ...
    implementation("com.github.quickbirdstudios.NonEmptyCollections:NonEmptyCollections:1.1.0")
}

👤 Author

This Kotlin library is created with ❤️ by QuickBird Studios.

❤️ Contributing

Open an issue if you need help, if you found a bug, or if you want to discuss a feature request.

Open a PR if you want to make changes to NonEmptyCollections.

📃 License

NonEmptyCollections is released under an MIT license. See License for more information.

Comments
  • API Suggestion: Replace/remove all

    API Suggestion: Replace/remove all "unsafe" toNonEmptyFoo extensions and rename the nullable ones

    For example, you have:

    fun <T> List<T>.nonEmptyOrNull() = if (isEmpty()) null else toNonEmptyList()
    

    and

    @UnsafeNonEmptyCollectionApi
    fun <T> Iterable<T>.toNonEmptyList(): NonEmptyList<T> = isAlreadyNonEmptyOr {
        nonEmptyListOf(first(), drop(1))
    }
    

    If it were me, I'd probably be lazy and just drop the whole unsafe set. The user can always just do:

    val nonEmpty = someList.nonEmptyOrNull() ?: error("Bug! I expected this to be non-empty!")
    

    But if you keep both APIs, I suggest at least naming both sets with the "toNonEmptyFoo" style. A lot of methods in the Kotlin standard library have names like toList, so going with toNonEmptyList seems like a good match.

    opened by ragnese 2
  • NonEmptyCollection should use out param to match Collection

    NonEmptyCollection should use out param to match Collection

    i.e., interface NonEmptyCollection<out T>: Collection<T> because Collection is defined as interface Collection<out T>.

    Then NonEmptyList, NonEmptySet, NonEmptyMap should also use out params.

    opened by ragnese 1
  • NonEmptyCollection shouldn't throw exceptions for deprecated API methods

    NonEmptyCollection shouldn't throw exceptions for deprecated API methods

    It doesn't hurt anything for them not to.

    But, I don't actually know how to implement the firstOr or ifEmpty ones. It might be better to just leave them alone (as in: don't override them at all).

    firstOrNull() is easy, though:

    fun firstOrNull(): T = first()
    
    opened by ragnese 1
  • Corrects NonEmptyList.plus(T) accidentally calling one of the locally…

    Corrects NonEmptyList.plus(T) accidentally calling one of the locally…

    … defined plus operators...

    NonEmptyList.plus(List) is redundant with NonEmptyList.plus(Iterable). Optimize NonEmptyList.plus(Sequence) and NonEmptyList.plus(Array) to not allocate a temporary List.

    opened by ragnese 1
  • More efficient implementation of NonEmptyList

    More efficient implementation of NonEmptyList

    Similar to my comments on Reddit :)

    Notice a few things:

    • NonEmptyList only holds one reference.
    • NonEmptyList.equals() is much more efficient than current main branch implementation. The main implementation is creating a new list every single time someone checks equality.
    • the head, tail constructor does one allocation instead of two.
    • All of the plus operators do less work. Some do significantly less work (e.g., List.plus(value): NonEmptyList).
    • Since plus operations will only ever increase the size of the list, there is no need to use the "safe" constructor- which also helps the performance gains mentioned above.
    • The plus operations that involve a NonEmptyList intentionally unwrap it so that we don't end up with a deeply nested object after many plus operations. This would be a space leak.

    The same approach could be applied to the other collections, but I wanted to just PR this one first before wasting my time :)

    opened by ragnese 1
Releases(1.1.0)
Owner
QuickBird Studios
Overly friendly team of developers driven to push the state of Mobile Development forward (we're hiring!)
QuickBird Studios
Repositório criado para ser utilizado pelo projeto de Kotlin Collections desenvolvido em Kotlin nas aulas feitas através da plataforma Alura.

Projeto Kotlin Collections Repositório criado para ser utilizado pelo projeto de Kotlin Collections desenvolvido em Kotlin nas aulas feitas através da

Marcos Felipe 1 Jan 17, 2022
Checks if the given grammar is LL(k) for the given k

LL(k) Checker Checks if the given grammar is LL(k) for the given k Grammars Curr

furetur 1 Dec 19, 2021
HelloKMM - Hello World in Kotlin Multiplatform Mobile (new empty project)

Hello KMM! Hello World in Kotlin Multiplatform Mobile (new empty project) Gettin

Blake Barrett 1 Feb 2, 2022
Checks for app updates and automatically updates the current app if the new one in local storage have a different version

Silent Android App Update Sample This sample shows how to update Android app silently without user confirmation with a device owner app. It works on A

Hamdi Guerbej 1 May 14, 2022
This just checks what architecture an installed application is using for its libraries.

Architecture Checker This just checks what architecture an installed application is using for its libraries. About Recently, I've seen that many peopl

Rev 11 Jan 31, 2023
These files are included in an Android Studio Project for a Magic the Gathering Life Counter app. The app was written in Kotlin.

Magic-Life-Counter These files were created in Android Studio using Kotlin. Usage This app was made to keep track of life totals while playing the tra

null 0 Dec 24, 2021
Chain Relations is a small casual existential game about life, human needs and long-term relations.

Chain Relations Chain Relations is a small casual existential game about life, human needs and long-term relations. ChainRelations.360p.mp4 Game objec

Andrzej Novosiolov 4 Dec 2, 2022
Simple api wrapper for nekos.life

nekos-kt Simple api wrapper for nekos.life Installation Maven: <repositories> <repository> <id>jitpack.io</id> <url>https://jitpack.io</url>

cattyn 6 Oct 24, 2022
Kreds - a thread-safe, idiomatic, coroutine based Redis client written in 100% Kotlin

Kreds Kreds is a thread-safe, idiomatic, coroutine based Redis client written in 100% Kotlin. Why Kreds? Kreds is designed to be EASY to use. Kreds ha

Abhijith Shivaswamy 117 Dec 23, 2022
Esito ambition is to be your return type for suspending functions.

Esito ambition is to be your return type for suspending functions.

null 58 Oct 21, 2022
Firestore Kotlin Client with strict (and relaxed) type-system.

Firestore Kotlin Client with strict (and relaxed) type-system.

Vihang Patil 2 Mar 4, 2022
Lambë Language 7 Dec 21, 2022
Kotlin extension function provides a facility to "add" methods to class without inheriting a class or using any type of design pattern

What is Kotlin Extension Function ? Kotlin extension function provides a facility to "add" methods to class without inheriting a class or using any ty

mohsen 21 Dec 3, 2022
Bring type-safety to your GitHub actions' API!

GitHub Actions typing Bring type-safety to your GitHub actions' API! This is a GitHub action that validates your action's type specs (action-types.y(a

Piotr Krzemiński 23 Dec 18, 2022
The WeeBe application is a social media-type app built on Ktor framework

The WeeBe application is a social media-type app built on Ktor framework that allows users to exchange various content connected with mental health, motivation, psychology, and improving oneself. Users can share posts with texts, images, videos, and links, as well as discuss the content in the comment section

Perpetio 3 Aug 5, 2022
📒 NotyKT is a complete 💎Kotlin-stack (Backend + Android) 📱 application built to demonstrate the use of Modern development tools with best practices implementation🦸.

NotyKT ??️ NotyKT is the complete Kotlin-stack note taking ??️ application ?? built to demonstrate a use of Kotlin programming language in server-side

Shreyas Patil 1.4k Dec 26, 2022
A Zero-Dependency Kotlin Faker implementation built to leave you fully satisfied

Satisfaketion A Zero-Dependency Kotlin Faker implementation built to leave you fully satisfied ?? ... With your fake data How to Install ?? Satisfaket

Ryan Brink 7 Oct 3, 2022
Archimedes's implementation for the Java Virtual Machine (JVM)

Archimedes Give me a place to stand, and I shall move the earth. Archimedes's implementation for the Java Virtual Machine (JVM) Building From Source T

Archimedes 24 Aug 20, 2022
🗼 yukata (浴衣) is a modernized and fast GraphQL implementation made in Kotlin

?? yukata 浴衣 - Modernized and fast implementation of GraphQL made in Kotlin yukata is never meant to be captialised, so it'll just be yukata if you me

Noel 5 Nov 4, 2022