{"id":17248769,"url":"https://github.com/nomisrev/optikal","last_synced_at":"2025-04-14T04:45:08.760Z","repository":{"id":103228153,"uuid":"102127295","full_name":"nomisRev/optikal","owner":"nomisRev","description":"Optikal is an optics library for Kotlin strongly inspired by Scala Monocle","archived":false,"fork":false,"pushed_at":"2018-01-24T22:34:36.000Z","size":124,"stargazers_count":8,"open_issues_count":0,"forks_count":1,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-03-27T18:52:23.798Z","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/nomisRev.png","metadata":{"files":{"readme":"README-2.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}},"created_at":"2017-09-01T15:32:16.000Z","updated_at":"2021-06-07T19:08:48.000Z","dependencies_parsed_at":null,"dependency_job_id":"3ae303c9-5e5a-48ea-b20e-150ed5b69b31","html_url":"https://github.com/nomisRev/optikal","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nomisRev%2Foptikal","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nomisRev%2Foptikal/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nomisRev%2Foptikal/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nomisRev%2Foptikal/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nomisRev","download_url":"https://codeload.github.com/nomisRev/optikal/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248824665,"owners_count":21167343,"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-15T06:42:05.940Z","updated_at":"2025-04-14T04:45:08.732Z","avatar_url":"https://github.com/nomisRev.png","language":"Kotlin","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![Build Status](https://travis-ci.org/nomisRev/optikal.svg?branch=master)](https://travis-ci.org/nomisRev/optikal)\n\n# Optikal\n\nOptikal is an optics library for Kotlin strongly inspired by [Scala Monocle](https://julien-truffaut.github.io/Monocle/).\n\n## Motivation\n\n\u003e Optics are a group of purely functional abstractions to manipulate (get, set, modify, …) immutable objects.\n\nKotlin does a great job making java less verbose and concise. If you prefer \"strong\" types you probably prefer a `data class Token(val value: String)` instead of just a String.\nBut getters, setters don't compose, and when dealing with nested objects it could become cumbersome and extremely verbose hence Optikal.\n\nLet's examine the following example. We have the following class structure. With the below defined Employee.\n\n```\ndata class Street(val number: Int, val name: String)\ndata class Address(val city: String, val street: Street)\ndata class Company(val name: String, val address: Address)\ndata class Employee(val name: String, val company: Company)\n```\n\n```kotlin\nimport optikal.sample.*\n\nval employee = Employee(\"John\", Company(\"Awesome inc\", Address(\"Awesome town\", Street(23, \"awesome street\"))))\n```\n\nDue to some requirements we have to change all street names to be capitalize. Since we have the good practice of working with immutable objects, which kotlin favors, we cannot\nsimple mutate the name to be capitalized. Since we also care about performance we also don't want to create a new employee when we just need to change his address.\n\nSo we use the \"convenient\" copy method on data classes to give the employee a new company street name. Quite verbose... and in case we need to do something similar elsewhere we have\nto construct the same construct.\n\n\n```kotlin\nemployee.copy(\n        company = employee.company.copy(\n                address = employee.company.address.copy(\n                        street = employee.company.address.street.copy(\n                                name = employee.company.address.street.name.capitalize()\n                        )\n                )\n        )\n)\n```\n```kotlin\n// Employee(name=John, company=Company(name=Awesome inc, address=Address(city=Awesome town, street=Street(number=23, name=Awesome street))))\n```\n\nSo let's see how lenses can solve this problem!\n\n## Lens\n\n\u003e A microscope lens is used to magnify and observe objects\n\nSimilar to a microscope lens, an optikal lens is used to observe what is in a object (product type). In the following example we have a `Token` type which\ntypes a string token. We can create a lens for is which can then be used to see what is inside a Token object or to modify it.\n\n\n```kotlin\nimport optikal.*\n\ndata class Token(val value: String)\n\nval token = Token(\"1\")\n\nval tokenLens: Lens\u003cToken, String\u003e = Lens(\n    get= { token: Token -\u003e token.value },\n    set= { value: String -\u003e { token: Token -\u003e token.copy(value= value) } }\n)\n\ntokenLens.modify({ \"2\" }, token)\n```\n```kotlin\n// Token(value=2)\n```\n\n## Generating lenses\n\nIn the previous example we manually created a lens for a `Token`. Which is fine but verbose and boring, since we don't like boilerplate code we'd love\nif this could just be generated for us.\n\nIf we add the `@Lenses` annotation to a data class its lenses will be automatically generated for it. So let's simplify our first example with lenses.\n```\n@Lenses data class Street(val number: Int, val name: String)\n@Lenses data class Address(val city: String, val street: Street)\n@Lenses data class Company(val name: String, val address: Address)\n@Lenses data class Employee(val name: String, val company: Company)\n```\n```kotlin\nimport optikal.*\nimport optikal.sample.*\n\nval employeeStreetNameLens: Lens\u003cEmployee, String\u003e = employeeCompany() composeLens companyAddress() composeLens addressStreet() composeLens streetName()\n\nemployeeStreetNameLens.modify({ name -\u003e name.capitalize() }, employee)\n```\n```kotlin\n// Employee(name=John, company=Company(name=Awesome inc, address=Address(city=Awesome town, street=Street(number=23, name=Awesome street))))\n```\n## Getting started\n\n```kotlin\n\n\"UPLOAD TO MAVEN AND ADD HERE\"\n\n```\n\n# License\n\n    Copyright (C) 2017 The Optikal Author\n\n    Licensed under the Apache License, Version 2.0 (the \"License\");\n    you may not use this file except in compliance with the License.\n    You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n    Unless required by applicable law or agreed to in writing, software\n    distributed under the License is distributed on an \"AS IS\" BASIS,\n    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n    See the License for the specific language governing permissions and\n    limitations under the License.\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnomisrev%2Foptikal","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnomisrev%2Foptikal","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnomisrev%2Foptikal/lists"}