{"id":20440359,"url":"https://github.com/smakeev/swiftwhen","last_synced_at":"2025-10-24T05:52:56.656Z","repository":{"id":62455799,"uuid":"203848841","full_name":"smakeev/SwiftWhen","owner":"smakeev","description":"expression's type switch (When) for Swift.","archived":false,"fork":false,"pushed_at":"2023-06-22T18:25:35.000Z","size":75,"stargazers_count":9,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-04-10T04:39:33.158Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/smakeev.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,"zenodo":null}},"created_at":"2019-08-22T18:12:11.000Z","updated_at":"2023-06-03T20:23:25.000Z","dependencies_parsed_at":"2022-11-02T00:15:12.851Z","dependency_job_id":"b328da6a-0b3b-424b-80ee-fc3b5c8f502b","html_url":"https://github.com/smakeev/SwiftWhen","commit_stats":null,"previous_names":[],"tags_count":10,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/smakeev%2FSwiftWhen","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/smakeev%2FSwiftWhen/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/smakeev%2FSwiftWhen/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/smakeev%2FSwiftWhen/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/smakeev","download_url":"https://codeload.github.com/smakeev/SwiftWhen/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248643004,"owners_count":21138355,"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-11-15T09:23:50.090Z","updated_at":"2025-10-24T05:52:56.582Z","avatar_url":"https://github.com/smakeev.png","language":"Swift","funding_links":[],"categories":[],"sub_categories":[],"readme":"# SwiftWhen\n\n```When``` is similar to ```switch``` but could be used as an expression. \n\n```swift\nlet a = When(number)\n        .case(0) {\"Invalid number\"}\n        .case(1)\n        .case(2) {\"Number is too low\"}\n        .case(3) {\"Number is correct\"}\n        .case(4) {\"Numbe is almost correct\"}\n        .default(\"Number is too high\")\n```\n```When``` must be finished with ```default```. This is due to the safe approach. In fact ```when``` returns an ```optional```, so you can return nil in ```case``` or in default.\nAfter the first ```case``` matches ```When``` executes it's block (will be called an```action blockon``` -  on the right to the ```case``` statement).\n```case``` might ommit the block, in this case the first ```action block``` after this ```case``` will be called. This is a way of grouping several ```case``` statements.\nIf no ```action block``` found the ```default``` value will be provided by ```When```.\n\n```Action block``` is a block with any code returning value of the same type as is provided in ```default```.\n```Action block``` and\\or ```default``` could returns ```nil```\n```When``` could be used with types it is using.\n\n```swift\nlet b = When\u003cInt, String\u003e(number)\n\t.case(0) {\"Invalid number\"}\n\t.case(1)\n\t.case(2) {\"Number is too low\"}\n\t.case(3) {\"Number is correct\"}\n\t.case(4) {\"Numbe is almost correct\"}\n\t.default(\"Number is too high\")\n```\nAs always ```When``` returns an ```optional```, so the resulttype is ```String?```\nIf you whant ```When``` to return ```String``` instead do the following as one of possible solutions:\n```swift\nlet b1 = When(number)\n\t.case(0) {\"Invalid number\"}\n\t.case(1)\n\t.case(2) {\"Number is too low\"}\n\t.case(3) {\"Number is correct\"}\n\t.case(4) {\"Numbe is almost correct\"}\n\t.default(nil) ?? \"Number is too high\"\n```\n\n```case``` could use not only a value but a condition block (``` (Type) -\u003e Bool  ``` )\n```swift\nlet state = When\u003cState, Int\u003e(stateToTest)\n\t.case({ $0 == .idle || $0 == .preparing || $0 == .ready}) { 0 }\n\t.case({ $0 == .working || $0 == .pausing}) { 1 }\n\t.case({ $0 == .finished }) {2}\n\t.default(3)\n```\n\nNote that  ```case``` with value could be used only for ```Equtable``` types while ```case``` with condition block could be used for any type.\n\nYou can combine ```case``` types.\n```swift\nlet b2 = When(number)\n\t.case({$0 \u003c 0}) {\"Number should be \u003e 0\"}\n\t.case(0) {\"Invalid number\"}\n\t.case(1)\n\t.case(2) {\"Number is too low\"}\n\t.case(3) {\"Number is correct\"}\n\t.case(4) {\"Numbe is almost correct\"}\n\t.default(nil) ?? \"Number is too high\"\n```\n\nSometimes you don't have many cases but the only one rule to make a result on one type from a value of another one.\nIn this case you may use ```when``` - a global function to have it as a statement and be used inline.\n```swift\nlet c = when(number) {\n\t//Here could be any culculations \n\treturn $0 \u003e= 10 ? \"Big number\" : \"Small number\"\n}\n```\n# More functions in 2.0.0\n```swift\n func with\u003cType\u003e(_ source: Type, handler: (Type) -\u003e Void)\n ```\n It could be used to\n \n```Optinal``` has an extension with several new methods\n```swift\nfunc takeWhen(_ handler: (Wrapped) -\u003e Bool) -\u003e Wrapped?\nfunc `let`\u003cResult\u003e(_ handler: (Wrapped) -\u003e Result?) -\u003e Result?\nfunc apply(_ handler: (Wrapped) -\u003e Void) -\u003e Wrapped?\nfunc run(_ handler: (Wrapped) -\u003e Void)\n```\n\nIn project's tests could be found examples:\n```swift\n\tclass A1 {\n\t\tvar str: A2 = A2()\n\t\tclass A2 {\n\t\t\tvar str: A3 = A3()\n\t\t\tclass A3 {\n\t\t\t\tvar str: String = \"A3\"\n\t\t\t}\n\t\t}\n\t}\n\t\n\tfunc testWith() {\n\t\tlet a = A1()\n\t\twith(a.str.str) {\n\t\t\tXCTAssert($0.str == \"A3\")\n\t\t}\n\t\n\t}\n\t\n\tfunc testLet() {\n\t\tlet a: A1? = A1()\n\t\tlet str = a.let {\n\t\t\t$0.str.str.str\n\t\t}\n\t\tXCTAssert(str == \"A3\")\n\t}\n\t\n\tfunc testRunMethod() {\n\t\tlet a: A1? = A1()\n\t\ta.run {\n\t\t\tlet str = $0.str.str.str\n\t\t\tXCTAssert(str == \"A3\")\n\t\t}\n\t}\n\t\n\tfunc testApply() {\n\t\tlet a: A1? = A1()\n\t\t_ = a?.str.str.str\n\t\ta.apply {\n\t\t\t$0.str.str.str = \"New A3\"\n\t\t}\n\t\t\n\t\ta.map {\n\t\t\tXCTAssert($0.str.str.str == \"New A3\")\n\t\t}\n\t\t\n\t\ta.apply {\n\t\t\t$0.str.str.str = \"first iteration\"\n\t\t}.apply {\n\t\t\t$0.str.str.str = \"second iteration\"\n\t\t}.apply {\n\t\t\t$0.str.str.str = \"third iteration\"\n\t\t}\n\n\t\ta.map {\n\t\t\tXCTAssert($0.str.str.str == \"third iteration\")\n\t\t}\n\t}\n\t\n\tfunc testTakeWhen() {\n\t\tvar a: Int? = 2\n\n\t\tif let validA = a.takeWhen({$0 \u003e 1}) {\n\t\t\tXCTAssert(validA == 2)\n\t\t} else {\n\t\t\tXCTAssert(false)\n\t\t}\n\t\t\n\t\ta = 1\n\t\tif let _ = a.takeWhen({$0 \u003e 1}) {\n\t\t\tXCTAssert(false)\n\t\t} else {\n\t\t\tXCTAssert(a == 1)\n\t\t}\n\n\t\ta = nil\n\t\tif let _ = a.takeWhen({$0 \u003e 1}) {\n\t\t\tXCTAssert(false)\n\t\t} else {\n\t\t\tXCTAssert(a == nil)\n\t\t}\n\n\t\ta = 100\n\t\tif let _ = a.takeWhen({$0 \u003e 1}) {\n\t\t\tXCTAssert(a == 100)\n\t\t} else {\n\t\t\tXCTAssert(false)\n\t\t}\n\t\t\n\t\tif let validA = a.takeWhen({$0 \u003e 1}).takeWhen({$0 == 100}) {\n\t\t\tXCTAssert(validA == 100)\n\t\t} else {\n\t\t\tXCTAssert(false)\n\t\t}\n\t}\n```\n\n```When``` could be used without parameter\n\n```swift\n\tlet value = 3\n\tlet result = When()\n\t    .case({ value == 1}) { 1 }\n\t    .case(100.2 == 100.3) { 2 }\n\t    .case({ value \u003e= 3}) { 3 }\n\t    .case(\"str\" == \"str\") { -100 }\n\t    .default(nil) ?? 0\n```\nAlso see what's new in 2.0.0 to see how to use ```When``` without parameter in new 2.0.0 syntax.\n\n# Operators:\n\n```SwiftWhen``` provides shorter way to achive expression of casting one value to another type value using some operators.\nThis might be shorter but harder to read. \n\n```swift\nlet result = state == .finished =\u003e { 0 } =\u003e? {\n\tstate == .working || state == .pausing =\u003e { 1 } =\u003e? {\n\t\t state == .idle || state == .preparing || state == .ready =\u003e { 2 } =\u003e! {\n\t\t\t3\n\t\t }\n\t}\n}\n```\nComprehensive description of operators could be found in project wiki page https://github.com/smakeev/SwiftWhen/wiki. \nBut to understand this you may think that:\n```=\u003e``` is an if statement. (Left part is a condition right is a then branch. \n```=\u003e?``` works like ```else if``` (and it should contain ```=\u003e``` in it's right part)\n```=\u003e!``` works like ```else``` and plays a role of a ```default``` statement.\n\nThe reault of this operator's chain will be an optional ```Int```. If you whant to have ```Some``` Int you will find that it is imposible just to add ?? to the end of the chain to unwrap it. The possible solution could be:\n```swift\nvar nonOptionalResult = 3\nnonOptionalResult =? state == .finished =\u003e { 0 } =\u003e? {\n\tstate == .working || state == .pausing =\u003e { 1 } =\u003e? {\n\t\tstate == .idle || state == .preparing || state == .ready =\u003e { 2 }\n\t}\n}\n```\n\nHere ```=?``` is an operator which assign right value to the left local only if right value is not nil, otherwise it does not change it. The default result here was assigned to the ```nonOptionalResult``` at the initialization process.\n\n# How to use:\n\n```SwiftWhen``` source contains only one source file ```SwiftWhen.swift```, so the easiest way is to copy it inside your project as is.\n\nAnother way is to add ```SwiftWhen``` as a subproject.\n\nIn this case you will need to add importing in files where you want to use it.\n```swift\nimport SwiftWhen\n```\n\nYou may use cocoapods https://cocoapods.org/pods/SomeWhen\n```\npod \"SomeWhen\"\n```\nNote, you will need add \n```swift \nimport SomeWhen\n```\n\n# What's new in 2.0.0\n\nNew 2 variants of syntax available:\nSymple: \n```swift\n\t\tlet source = 5\n\t\tlet result = When(.simple, source) {\n\t\t\t$0(0) =\u003e \"Zero\"\n\t\t\t$0(1) =\u003e \"One\"\n\t\t\t$0(2) =\u003e \"Two\"\n\t\t\t$0(3) =\u003e \"Three\"\n\t\t\t$0(false) =\u003e \"Four\"\n\t\t\t$0(true) =\u003e {\n\t\t\t\treturn \"Five\"\n\t\t\t}()\n\t\t\t$0(6) =\u003e \"Six\"\n\t\t\t$0(7) =\u003e \"Seven\"\n\t\t\t$0(8) =\u003e \"Eight\"\n\t\t\t$0(9) =\u003e  \"Nine\"\n\t\t}.default(\"default\")\n```\nBy adding ```.simple``` you could just provide cases in ```$0``` statement and provide according value after ```=\u003e```\nIn case of several cases have the same result you may just ommit ```=\u003e``` for cases besides the last one.\nBut in this case the compiler will show a warning.\nTo remove the warning you could use ```.skip```\n## Note: ```.simple``` case is only applicable when you provide a simple result.\nIn case of you need to call a function this is a bad idea due to all of them will be called.\n\n```swift\n\t\tlet a1 = 2\n\t\tlet b1 = When(.simple, a1) {\n\t\t\t$0(0) =\u003e \"Zero\"\n\t\t\t$0(1) =\u003e \"One\"\n\t\t\t$0(2) =\u003e .skip\n\t\t\t$0(3) =\u003e .skip\n\t\t\t$0(4) =\u003e .skip\n\t\t\t$0(5) =\u003e \"Five\"\n\t\t\t$0(6) =\u003e \"Six\"\n\t\t\t$0(7) =\u003e \"Seven\"\n\t\t\t$0(8) =\u003e \"Eight\"\n\t\t\t$0(9) =\u003e  \"Nine\"\n\t\t}.default(nil) ?? \"Unknown\"\n```\n\nThe second variant of new syntax does not contain ```simple``` key word\n```swift\n\t\tlet b1 = When(a) {\n\t\t\t$0.case(0) =\u003e \"Zero\"\n\t\t\t$0.case(1) =\u003e \"One\"\n\t\t\t$0.case(2) =\u003e \"Two\"\n\t\t\t$0.case(3) =\u003e \"Three\"\n\t\t\t$0.case(4)\n\t\t\t$0.case(5) { \"Five\" }\n\t\t\t$0.case(6) =\u003e \"Six\"\n\t\t\t$0.case(7) =\u003e \"Seven\"\n\t\t\t$0.case(8) =\u003e \"Eight\"\n\t\t\t$0.case(9) =\u003e  \"Nine\"\n\t\t}.default(nil) ?? \"Unknown\"\n```\nIn this variant you may also use ```=\u003e``` to provide simple result. Also you could provide closures directly. As in case(5) here.\n\nAlso both variants of syntax supports ```When``` without an argument\n```swift\n\t\tlet result = When {\n\t\t\t$0.case(3 \u003e 5)\n\t\t\t.case({$0 == false})\n\t\t\t.case(6 \u003e 20)\n\t\t\t.case(false) { \"No way\" }\n\t\t\t$0.case(true) {\"true\"}\n\t\t}.default(nil) ?? \"Default\"\n```\n```swift\n\t\tlet result = When(.simple) {\n\t\t\t$0(3 \u003e 5) =\u003e \"1\"\n\t\t\t$0(6 \u003e 20) =\u003e \"2\"\n\t\t\t$0(false) =\u003e \"3\"\n\t\t\t$0(true) =\u003e \"true\"\n\t\t}.default(nil) ?? \"Default\"\n```\n\nOld syntax also supported. And it could be combined with new.\n\n### in 2.0.1 you can also use closure after =\u003e. Closure will be called only in case of ```case``` is correct.\nHere are examples:\n```swift\n\t\tlet testState = TestState.idle\n\n\t\tlet stateInt = When(.simple, testState) {\n\t\t\t\t$0(TestState.idle)      =\u003e { 0 }\n\t\t\t\t$0(TestState.preparing) =\u003e { nil }\n\t\t\t\t$0(TestState.ready)     =\u003e { 2 }\n\t\t\t\t$0(TestState.working)   =\u003e { 3 }\n\t\t\t\t$0(TestState.pausing)   =\u003e { 4 }\n\t\t\t\t$0(TestState.finished)  =\u003e { 5 }\n\t\t\t\t$0(TestState.wrong)     =\u003e { 6 }\n\t\t\t\t}\n\t\t\t\t.default(nil) ?? 0\n\n\t\tXCTAssert(stateInt == 0)\n\t\t\n\t\tlet stateInt1 = When(testState) {\n\t\t\t\t$0.case(TestState.idle)      =\u003e { 0 }\n\t\t\t\t$0.case(TestState.preparing) =\u003e { nil }\n\t\t\t\t$0.case(TestState.ready)     =\u003e { 2 }\n\t\t\t\t$0.case(TestState.working)   =\u003e { 3 }\n\t\t\t\t$0.case(TestState.pausing)   =\u003e { 4 }\n\t\t\t\t$0.case(TestState.finished)  =\u003e { 5 }\n\t\t\t\t$0.case(TestState.wrong)     =\u003e { 6 }\n\t\t\t\t}\n\t\t\t\t.default(nil) ?? 0\n\n\t\tXCTAssert(stateInt1 == 0)\n\n\t\tlet stateInt2 = When(.simple) {\n\t\t\t\t$0({testState == TestState.idle})      =\u003e { 0 }\n\t\t\t\t$0({testState == TestState.preparing}) =\u003e { nil }\n\t\t\t\t$0({testState == TestState.ready})     =\u003e { 2 }\n\t\t\t\t$0({testState == TestState.working})   =\u003e { 3 }\n\t\t\t\t$0({testState == TestState.pausing})   =\u003e { 4 }\n\t\t\t\t$0({testState == TestState.finished})  =\u003e { 5 }\n\t\t\t\t$0({testState == TestState.wrong})     =\u003e { 6 }\n\t\t\t\t}\n\t\t\t\t.default(nil) ?? 0\n\n\t\tXCTAssert(stateInt2 == 0)\n\t\t\n\t\tlet stateInt3 = When {\n\t\t\t\t$0.case({testState == TestState.idle})      =\u003e { 0 }\n\t\t\t\t$0.case({testState == TestState.preparing}) =\u003e { nil }\n\t\t\t\t$0.case({testState == TestState.ready})     =\u003e { 2 }\n\t\t\t\t$0.case({testState == TestState.working})   =\u003e { 3 }\n\t\t\t\t$0.case({testState == TestState.pausing})   =\u003e { 4 }\n\t\t\t\t$0.case({testState == TestState.finished})  =\u003e { 5 }\n\t\t\t\t$0.case({testState == TestState.wrong})     =\u003e { 6 }\n\t\t\t\t}\n\t\t\t\t.default(nil) ?? 0\n\n\t\tXCTAssert(stateInt3 == 0)\n\n```\n### in 2.0.2 you can use closure in default. Closure will be executed only if no cases worked.\n### Also now you can use `.else` instead of `.default`\n\n```swift\n\t\t\tlet a: Int = 5\n\t\t\n\t\tlet b = When(a)\n\t\t\t.case(0) {\"0\"}\n\t\t\t.case(1) {\"1\"}\n\t\t\t.default {\n\t\t\t\tif a \u003c 5 {\n\t\t\t\t\treturn \"less then 5\"\n\t\t\t\t} else {\n\t\t\t\t\treturn \" \u003e= 5\"\n\t\t\t\t}\n\t\t\t}\n\t\tXCTAssert(b == \" \u003e= 5\")\n\t\t\n\t\tlet c =  When\u003cInt, String\u003e(a) {\n\t\t\t\t   $0.case(0) =\u003e \"0\"\n\t\t\t\t   $0.case(1) =\u003e \"1\"\n\t\t\t\t}\n\t\t\t\t.else {\n\t\t\t\t\t   if a \u003c 5 {\n\t\t\t\t\t\t   return \"less then 5\"\n\t\t\t\t\t   } else {\n\t\t\t\t\t\t   return \" \u003e= 5\"\n\t\t\t\t\t   }\n\t\t\t\t   }\n\t\tXCTAssert(c == \" \u003e= 5\")\n```\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsmakeev%2Fswiftwhen","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsmakeev%2Fswiftwhen","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsmakeev%2Fswiftwhen/lists"}