{"id":17767661,"url":"https://github.com/fablue/imko","last_synced_at":"2025-06-11T05:33:17.078Z","repository":{"id":215164199,"uuid":"100397361","full_name":"fablue/imko","owner":"fablue","description":"Immutable Kotlin Objects","archived":false,"fork":false,"pushed_at":"2017-08-15T19:37:14.000Z","size":41,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-04-01T14:19:54.600Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Kotlin","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/fablue.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-08-15T16:32:23.000Z","updated_at":"2017-08-15T16:42:02.000Z","dependencies_parsed_at":null,"dependency_job_id":"785e52c5-68e6-4b6e-b105-0482c3112652","html_url":"https://github.com/fablue/imko","commit_stats":null,"previous_names":["fablue/imko"],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fablue%2Fimko","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fablue%2Fimko/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fablue%2Fimko/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fablue%2Fimko/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/fablue","download_url":"https://codeload.github.com/fablue/imko/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fablue%2Fimko/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":259207825,"owners_count":22821773,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-26T20:50:17.037Z","updated_at":"2025-06-11T05:33:17.060Z","avatar_url":"https://github.com/fablue.png","language":"Kotlin","funding_links":[],"categories":[],"sub_categories":[],"readme":"# imko\n## Immutable Kotlin Objects\n### What is imko?\nImko lets you define truly immutable objects in Kotlin in a very efficient way and intuitive syntax. It also solves the problem of \"nested immutability\". Meaning the problem of your immutable object containing multiple other non-trivial objects.\n\n```\nObject 1\n| \\\n|  \\\n|   Object 2\n|   |   \\\n|   |    \\\n|   |      Int 2\n|   Int 1   \n|\nString\n```\n\nIn the example above, Object 2 is considered as non-trivial because it holds references to two other variables. Imko defines a very cool syntax of getting mutations of this object.\n\nFor this example, getting a version with int2 being doubled:\n\n```kotlin\nval version2 = \nobject1{\n        object2{\n              int2{\n                  times(2)\n               }\n        }\n    }\n```\n\nOr alternatively, written in a more compact way\n\n```kotlin\nval version2 = object1{ object2{ int2{ times(2) } } }\n```\n\n------------\n____________\n\n### Setup\n#### gradle\n```\n\tallprojects {\n\t\trepositories {\n\t\t\t...\n\t\t\tmaven { url 'https://jitpack.io' }\n\t\t}\n\t}\n```\n\n```\ndependencies {\n\t        compile 'com.github.fablue:imko:1.0-alpha.1'\n\t}\n\n```\n\n#### Other dependency managers\nhttps://jitpack.io/#fablue/imko/1.0-alpha.1\n\n\n\n------------\n____________\n\n\n### Usage\nI will explain how to use imko by using the [AliG example](https://github.com/fablue/imko/blob/master/example/src/ImkoExample.kt). \n\n#### Creating an immutable object\nLet's build an immutable definition of a car with various properties!\nThis is very similar to defining plain old Kotlin objects. Start a class which extends from Immutable\n\n```kotlin\nclass Car : Immutable\u003cCar\u003e(){\n}\n```\n\nThe first thing to notice here is, that we have to pass the actual implementation to the Immutable as type param. There is little to no reason for passing in any other super-type of the implementation. \n\nDefining variables and values is done by using the ```kotlin ivar()``` and ```kotlin ival()``` functions. Let's assume that our car should have a color and an engine as variables\n\n```kotlin\nclass Car : Immutable\u003cCar\u003e(){\n   val color = ivar(Color.BLUE)\n   val engine = ivar(Engine(cylinders = 6))\n}\n```\n\nThe second thing we notice here is: All attributes of immutable objects are defined using the ```val``` keyword. You can see here, that the syntax is very similar to creating poko's. \n\nSo let's say we want to have a model number which cannot be changed at all and is passed to the object using a constructor\n\n```kotlin\nclass Car(modelNumber: Long) : Immutable\u003cCar\u003e() {\n    /*\n    Always provide an empty constructor, so the system is able to instantiate a new car\n    */\n    constructor() : this(-1)\n    /**\n     * The cars model number (cannot be changed)\n     */\n    val modelNumber = ival(modelNumber)\n    val color = ivar(Color.BLUE)\n    val engine = ivar(Engine(cylinders = 6))\n}\n```\n\nThis is pretty straight forward as well. The third thing to notice: Providing an empty constructor is essential to make sure that the system can instantiate a new car for you. Don't worry the -1 does not appear in any mutations :relaxed:\n\nLet's create an Engine and a TuningKit definition in a similar fashion:\n\n```kotlin\nclass TuningKit(boost: Int) : Immutable\u003cTuningKit\u003e() {\n    constructor() : this(0)\n\n    /**\n     * Defines how many ps per cylinder are boosted\n     */\n    val boostPerCylinder = ivar(boost)\n}\n\nclass Engine(cylinders: Int) : Immutable\u003cEngine\u003e() {\n    constructor() : this(0)\n\n    /**\n     * Defines how many ps each cylinder has. This\n     * cannot be changed\n     */\n    val baselinePower = ival(25)\n\n    /**\n     * The number of cylinders cannot be changed\n     */\n    val cylinders = ival(cylinders)\n\n    /**\n     * But the tuning\n     */\n    val tuningKit = ivar\u003cTuningKit?\u003e(null)\n}\n```\n\n\n------------\n____________\n\n### Creating different versions of a car\nWe add a little function telling us the power of the car into car \n```kotlin\n    fun power(): Int {\n        val cylinders = engine().cylinders()\n        val baselinePower = engine().baselinePower()\n        val tuningBoost = engine().tuningKit()?.boostPerCylinder?.get() ?: 0\n        return cylinders * (baselinePower + tuningBoost)\n    }\n```\n______\nStart by using a car with model number 1\n```kotlin\n    val firstCar = Car(modelNumber = 1)\n    print(firstCar.power())     //Our first car has 150 ps!   //150\n    print(firstCar.color())     // And it is blue!            //java.awt.Color[r=0,g=0,b=255]\n```\nIt obviously has 150 ps and is blue!\n\n_______\nSo let's create a yellow version of the car!\n```kotlin\n    //lets get a yellow version of the car\n    val yellowCar = firstCar.color { Color.YELLOW }\n\n    // Now we have two nearly identical cars: One blue, One yellow.\n    // Color of the first car: java.awt.Color[r=0,g=0,b=255] ; second car: java.awt.Color[r=255,g=255,b=0]\n    print(\"Color of the first car: ${firstCar.color()} ; second car: ${yellowCar.color()}\")\n\n```\n You can see, that we created a new version of the car sharing all attributes with the old version except, that it is yellow now! We used the invoke operator to create this version\n________\nLet's get a tuned version of our yellow car to demonstrate how nested immutability can be handled!\n\n```kotlin\n    //Lets tune the yellow car!\n    val tunedYellowCar = yellowCar {\n        engine {\n            tuningKit {\n                TuningKit(15)\n            }\n        }\n    }\n    \n    \n    // We now have a tuned version of our yellow car!\n    // Power: yellow car: 150 ;  tuned version: 240\n    print(\"Power: yellow car: ${yellowCar.power()} ;  tuned version: ${tunedYellowCar.power()}\")\n```\n\nPretty nice, hmm? :relaxed: \n\nYou are free to write it even in a very compact way: \n\n```kotlin\n    tunedYellowCar = yellowCar { engine { tuningKit { TuningKit(boost = 15) } } }\n```\n\n__________\nNow let's get crazy and even mutate the tuningKit to get a new version of the car and explore another need feature. \nSay we want to create a monster version of our car by multiplying the number of cylinders with the current boost per cylinder. \n\n```kotlin\n    //But now we want to get professional with our yellow car. We want to further tune it, but instead\n    //Of simply defining another boost we want to multiply the current boost with the count of cylinders\n\n    val monsterCar = tunedYellowCar {\n        engine {\n            tuningKit {\n                this?.boostPerCylinder?.mutate {\n                    // You have access to the number of cylinders here.\n                    // This is extremely cool, because it is part of the engine\n                    // but technically not part of the tuning kit\n                    cylinders() * this\n                }\n            }\n        }\n    }\n\n    // It worked! We have a monster version of our car!..: AliG would be proud of his yellow monster\n    //Power: tuned car: 240 ;  monser version: 690\n    print(\"Power: tuned car: ${tunedYellowCar.power()} ;  monser version: ${monsterCar.power()}\")\n```\n\nAs you can see: You have access of the cylinders() attribute of the engine when mutating the tuningKit. \n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffablue%2Fimko","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffablue%2Fimko","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffablue%2Fimko/lists"}