{"id":16931647,"url":"https://github.com/jesseduffield/ok","last_synced_at":"2025-04-05T08:06:31.784Z","repository":{"id":47706278,"uuid":"396275995","full_name":"jesseduffield/OK","owner":"jesseduffield","description":"Welcome to the future of programming languages: OK?","archived":false,"fork":false,"pushed_at":"2022-12-13T18:37:12.000Z","size":411,"stargazers_count":558,"open_issues_count":10,"forks_count":19,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-03-29T07:06:15.421Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Go","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/jesseduffield.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}},"created_at":"2021-08-15T08:20:26.000Z","updated_at":"2025-03-27T23:36:03.000Z","dependencies_parsed_at":"2023-01-28T14:17:54.536Z","dependency_job_id":null,"html_url":"https://github.com/jesseduffield/OK","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/jesseduffield%2FOK","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jesseduffield%2FOK/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jesseduffield%2FOK/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jesseduffield%2FOK/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jesseduffield","download_url":"https://codeload.github.com/jesseduffield/OK/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247305933,"owners_count":20917208,"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-13T20:44:26.454Z","updated_at":"2025-04-05T08:06:31.761Z","avatar_url":"https://github.com/jesseduffield.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# _OK?_\n\n_Try it out on the [playground](https://www.okquestionmark.org/)_\n\n_Watch the [Making-of video](https://www.youtube.com/watch?v=PLGpUsSL0FI\u0026ab_channel=JesseDuffield)_\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"assets/quentyn_vectorised.png\" width=\"500px\"/\u003e\n  \u003cp align=\"center\"\u003e\u003ci\u003eOK?'s mascot: Quentyn Questionmark.\u003c/i\u003e\u003c/p\u003e\n\u003c/p\u003e\n\n## Programming Is Simple Again\n\n_OK?_ is a modern, dynamically typed programming language with a vision for the future.\n_OK?_'s mission is to do away with the needless complexity of today's programming languages and let you focus on what matters: writing code that makes a difference.\n\n### Contents\n\n- [Conditionals](#conditionals)\n- [Readable Switches](#readable-switches)\n- [Nulls Are Not OK](#nulls-are-not-ok)\n- [Error Handling](#error-handling)\n- [Readable Logical Operators](#readable-logical-operators)\n- [One Comparison Operator](#one-comparison-operator)\n- [Dead-simple Operator Precedence](#dead-simple-operator-precedence)\n- [Death To Classes](#death-to-classes)\n  - [All Fields Are Private](#all-fields-are-private)\n  - [No Constructors](#no-constructors)\n  - [Evolution Over Composition](#evolution-over-composition)\n- [Familiarity Admits Brevity](#familiarity-admits-brevity)\n- [Concurrency, Iterated](#concurrency-iterated)\n- [Testimonials](#testimonials)\n- [How To Get Started](#how-to-get-started)\n- [Credits](#credits)\n\n### Conditionals\n\nVery early on in its design, it was decided that _OK?_ would not feature a ternary operator. For those unaware, the ternary operator looks like this:\n\n```js\nlet a = isprod ? 'prod' : 'dev';\n```\n\nDisgusting, we agree. Einstein, Tesla, and Newton all died long ago, so there's really only a handful of humans left on Earth who are capable of parsing that stupifying syntax. What does the question mark mean? What does the colon mean? In _OK?_ we leave those questions for the philosophers and focus on what's important: _writing clean code_.\n\nA language only needs one conditional control flow construct, and in _OK?_, that construct is the switch statement. Switch statements are more versatile and expressive than ternary operators and if statements, and after a while you'll forget those other constructs ever existed. Here's the above statement in idiomatic _OK?_:\n\n```go\nlet a = switch isprod {\n  case true: \"prod\";\n  case false: \"dev\";\n}\n```\n\nThe switch form, although longer, is unquestionably clearer. Understanding the value of simplicity over complexity is the first step to learning _OK?_\n\n### Readable Switches\n\nGiven that switches are so central to _OK?_, we wanted to avoid some common pitfalls around switches found in other languages. In other languages it's common to have a single switch statement take up several pages of an editor with bloated logic being shoved into each switch case, so in _OK?_ we made it that you can only have _one_ statement per case:\n\nIf you want to execute multiple statements per switch case, just wrap them in a function:\n\n```go\n// INVALID:\nswitch x {\n  case true:\n    z = z + 2\n  case false:\n    x = x + 1;\n    y = y - 1; // \u003c-- ERROR: switch blocks can only contain a single statement\n}\n\n// VALID:\nlet onfalse = fn() {\n  x = x + 1;\n  y = y - 1;\n};\n\nswitch x {\n  case true: z = z + 2;\n  case false: onfalse();\n}\n```\n\nThis ensures separation of concerns: the specific per-case logic is factored away, bringing the cases themselves to the forefront.\n\n### Nulls Are Not OK\n\nNull values, famously dubbed the [billion dollar mistake](https://www.infoq.com/presentations/Null-References-The-Billion-Dollar-Mistake-Tony-Hoare/). I want my money back Tony Hoare.\n\nImplicit nullability is a thorn in the side of every self-respecting developer and that's why in _OK?_, null values are _NOT_ OK, _OK?_\n\nWe could have omitted null values from _OK?_, but then you might forget how bad they are, so we've included them, represented not as `nil` or `null` but as `NO!`, which is the only sensible answer to the question _Are nulls OK?_\n\nTo drive the point home, we've also added a builtin function named `ayok?` which takes a value and returns whether that value is OK.\n\n```go\nlet x = NO!\nputs(ayok?(x)) // prints 'false'\n\nlet y = 10\nputs(ayok?(y)) // prints 'true'\n```\n\nNow when your colleagues ask whether nulls are OK, you'll know exactly what to say.\n\n### Error Handling\n\nIn _OK?_, errors are simply values, just like any other value. One value they're particularly similar to is strings, and that's because by convention, they actually are strings. For example:\n\n```go\nlet divide = fn(a, b) {\n  return switch b {\n    case 0: [NO!, \"cannot divide by zero\"];\n    default: [a / b, \"\"];\n  };\n};\n\nresult = divide(5, 0)\nswitch result[1] {\n  case \"\": puts(result[0])\n  default: puts(result[1]) // prints \"cannot divide by zero\"\n}\n```\n\nNo magic, just arrays and strings.\n\n### Readable Logical Operators\n\nEver come across a conditional statement that chains a heap of long boolean expressions together?\n\n```go\nswitch p.isactive() \u0026\u0026 p.credits() \u003e= reqcreds \u0026\u0026 p.nottype(\"Admin\") {\n  ...\n}\n```\n\nI think I pulled a neck muscle trying to read that obscenely long line.\n\nIn _OK?_, the `\u0026\u0026` and `||` operators can only act on variables, so that it's possible for the reader to understand what's going on.\n\n```go\n// ERROR: '\u0026\u0026' operator must act on variables\nswitch p.isactive() \u0026\u0026 p.credits() \u003e= reqcreds \u0026\u0026 p.nottype(\"Admin\") {\n  ...\n}\n```\n\nHere's how the above switch statement would be done in _OK?_\n\n```go\nlet isactive = p.isactive()\nlet enoughcr = p.credits() \u003e= reqcreds\nlet notadmin = p.nottype(\"Admin\")\nswitch isactive \u0026\u0026 enoughcr \u0026\u0026 notadmin {\n  ...\n}\n```\n\nThis reflects a central tenet of _OK?_: _be kind to the reader_.\n\nIf you need to short-circuit your conditionals, you can use the `lazy` keyword:\n\n```go\nlet isactive = p.isactive()\nlet enoughcr = lazy p.credits() \u003e= reqcredits\nlet notadmin = lazy p.nottype(\"Admin\")\nswitch isactive \u0026\u0026 enoughcr \u0026\u0026 notadmin {\n  ...\n}\n```\n\nIf `p.isactive()` returns `false`, then `p.credits()` and `p.usertype()` will never be called.\n\nWith this feature you get the best of both worlds: clean, readable code, without sacrificing performance.\n\n### One Comparison Operator\n\nEver found yourself running in circles looking for the right comparison operator? Instead of wasting time memorising the hieroglyphics of `==`, `!=`, `\u003e`, `\u003c`, `\u003e=`, and `\u003c=`, what if we told you that you only needed one?\n\n_OK?_ features a single comparison operator: `\u003e=`\n\n| In other languages | In _OK?_                                         |\n| ------------------ | ------------------------------------------------ |\n| `a \u003e= b`           | `a \u003e= b`                                         |\n| `a \u003c= b`           | `b \u003e= a`                                        |\n| `a \u003e b`            | `!(b \u003e= a)`                                      |\n| `a \u003c b`            | `!(a \u003e= b)`                                      |\n| `a == b`           | `let x = a \u003e= b; let y = b \u003e= a; x \u0026\u0026 y`         |\n| `a != b`           | `let x = !(a \u003e= b); let y = !(b \u003e= a); x \\|\\| y` |\n\nThis means that instead of juggling six different comparison operators in your head you can focus on what matters: creating great software.\n\nIn the _OK?_ standard library we haven't found the need to extract any of these expressions into their own functions, but there's nothing stopping you from rolling your own:\n\n```go\nlet equals = fn(a, b) {\n  let x = a \u003e= b;\n  let y = lazy b \u003e= a;\n  return x \u0026\u0026 y;\n}\n```\n\n### Dead-simple Operator Precedence\n\nin _OK?_, `5 + 2 * 3` evaluates to 21, not 11, because addition and multiplication have equal operator precedence. If you want to evaluate your expression in some other order, you simply need to use parentheses: `5 + (2 * 3)`.\n\nThis simple left-to-right default spares you from scrounging around the internet looking for an operator precedence table, and lets you keep your eyes on the code.\n\n### Death To Classes\n\nThe authors of _OK?_ watched as object-oriented (OO) languages boomed in popularity, only to find them soon buckling under their own weight. Central to this clinical obesity is the _class_.\n\nA class takes a sensible idea: defining data along with methods that act on that data, and then drives it off a cliff by adding inheritance and subtype polymorphism. It should be no surprise that a bunch of class-obsessed aristocratic oldies in the 60s, who probably spent all their time deciding which child should inherit most of the estate, decided to add a construct named 'class' which revolved around inheritance.\n\nWell, the revolution has finally come! There is no inheritance in _OK?_, in solidarity with all those who fought against the bourgeoisie in years past. Some other languages opted for _structs_ over classes yet despite their developers honourably denouncing OO, old habits die hard with some accidentally uttering 'class' when they mean 'struct'. Some developers even say 'class' deliberately, a dogwhistle to return to the old days when the OO aristocracy still held the developer profession by the throat.\n\nTo remove any ambiguity and to ensure full commitment to the death of classes, we've decided to use our own terminology: 'notaclass' , or 'nac' for short.\n\n```go\nnotaclass person {\n  field name\n  field email\n}\n```\n\nLet's deep dive into what makes our nacs special:\n\n#### All Fields Are Private\n\nYou don't check how your friend is feeling by prying them open with a crowbar and perusing through their entrails; you just _ask_ them. The same is true in programming. There is no way to mark a field as public in _OK?_ because the public API of a nac should describe _behaviour_, not _state_.\n\n```go\nlet p = new person()\np.name = \"Jesse\" // \u003c-- ERROR: access of private field 'name'\n```\n\nFor extenuating circumstances, you can define a _privacy acknowledgement_ with the `pack` keyword, allowing external code to access a nac's fields if they include the acknowledgement in a comment, preceded by 'I acknowledge that':\n\n```go\nnotaclass person {\n  pack \"I am a stupid piece of shit who should not be doing this\"\n\n  field name\n  field email\n}\n\nlet p = new person()\n// I acknowledge that I am a stupid piece of shit who should not be doing this\np.name = \"Jesse\"  // \u003c-- No error\n\n```\n\nThis makes it easy to find privacy violations with `CTRL+F` and lets you communicate your tolerance level explicitly.\n\n#### No Constructors\n\nWhat part of `notaclass` don't you understand? Constructors are a class-based thing, and _OK?_ does not have classes. The word `Constructor` also contains the word `struct`, and _OK?_ does not have structs. If you want to define the initial state of a nac, just add it as a separate method:\n\n```go\nnotaclass person {\n  field name\n  field email\n\n  public init fn(selfish, name, email) {\n    selfish.name = name;\n    selfish.email = email;\n  }\n}\n\nlet p = new person()\np.init(\"Jesse\", \"jesse@test.com\")\n```\n\nNotice the first argument in that method: we considered using `self`, `this`, or `me`, for the receiver argument, but felt like these all had connotations that would confuse people if carried over into _OK?_. In _OK?_, receivers are just regular function arguments with no special scoping and no special treatment. But they are still kind of similar to receivers in other languages so we settled on _self-ish_, a sensible middle-ground. It's a word that accurately describes you, if you're the kind of person who disagrees with this convention.\n\n#### Evolution Over Composition\n\nYou may be familiar with the phrase 'Composition Over Inheritance'. That was cute but the world has moved on. Composition fixes the _fragile base-class_ problem introduced by Inheritance, only to introduce its own _useless base-component_ problem where you can't shake the feeling that you've actually handicapped yourself a bit by depending on composition for code reuse, especially when the component has no ability to interact with its parent.\n\nIt's time we take the next logical step: _Evolution Over Composition_. Instead of thinking in terms of _is-a_ or a _has-a_ relationships, think in terms of _becomes-a_ relationships. How does this work?\n\nTo enable evolution, you simply need to define an `evolve` method in your nac. The `evolve` method is invoked after any other of the nac's methods are executed, and it determines if the preconditions have been met to evolve the nac instance into a new nac type.\n\n```go\nnotaclass brgousie {\n  public whoami fn(selfish) {\n    return \"a good-for-nothing aristocrat who likes classes\"\n  }\n}\n\nnotaclass person {\n  field name\n  field email\n  field likeclas\n\n  ...\n\n  public whoami fn(selfish) {\n    return selfish.name;\n  }\n\n  public makeold fn(selfish) {\n    selfish.likeclas = true;\n  }\n\n  evolve fn(selfish) {\n    switch selfish.likeclas {\n      case true:\n        return new brgousie();\n      default:\n        return NO!;\n    }\n  }\n}\n\nlet p = new person();\np.init(\"John\", \"\")\nputs(p.whoami()); // prints \"John\"\np.makeold(); // evolve() method is called behind the scenes\nputs(p.whoami()); // prints \"a good-for-nothing aristocrat who likes classes\"\n```\n\nThis simple yet powerful feature enables a vast array of possibilities, without the frustration evoked by its predecessors.\n\n### Familiarity Admits Brevity\n\nAt some point, the High Counsel Of Programming Conventions got together and decided that variable names need to stretch for miles. It's time to reverse that decision. _Familiarity Admits Brevity_, which is why these days I don't even say goodbye before hanging up on my wife. You should be intimately familiar with your codebase, meaning all of your variables and method names should be short and sweet. You shouldn't need to use juvenile word separators like underscores or camelCase because if you can't capture the meaning of a variable in a single word, that's a sign that you need to refactor.\n\nFor this reason, it's idiomatic _OK?_ to limit all variable and method names to eight characters, all in lowercase, and without underscores.\n\nSome example abbreviations:\n\n| invalid                                | valid    |\n| -------------------------------------- | -------- |\n| characters                             | chars    |\n| MaximumPhysicalAddress                 | mxphsadr |\n| accrueYesterdaysYield()                | ayy()    |\n| hostEnterpriseYellowBorderBackground() | heybbg() |\n\nYou may disagree with this idiom, and that's okay, because it's enforced by the compiler. You're welcome.\n\n### Concurrency, Iterated\n\nWe've made it this far without talking about iteration or concurrency, and that's because in _OK?_, the two concepts are one and the same.\n\nNo modern language can be taken seriously without first-class concurrency support, yet we've found that for all that support, developers still forget to leverage concurrency in the one place that screams for it the most: loops.\n\n#### Introducing _OK?_'s `map` function\n\n_OK?_'s only concurrency construct is also its only loop construct: the `map` function.\n\n`map` behaves similar to map functions in other languages, except for one thing: the callbacks are _always_ executed concurrently.\n\nFor example, the following code snippet returns a result in one second:\n\n```go\nlet doubled = map([1,2,3], fn(e) {\n  sleep(1); // sleep one second\n  e * 2\n}); // [2,4,6] obtained in one second\n```\n\nIf you just want to compute two expensive values concurrently, you can use `map` with a switch:\n\n```go\nlet result = map([0,1], fn(e, i) {\n  switch i {\n  case 0:\n    return expnsiv1();\n  case 1:\n    return expnsiv2();\n  }\n});\nlet value1 = result[0];\nlet value2 = result[1];\n```\n\nWith the union of concurrency and iteration, the sky is the limit.\n\n```go\nlet every = fn(arr, check) {\n  let passed = true;\n  map(arr, fn(e) {\n    switch check(e) { case true: passed = false; } }\n  )\n  return passed;\n};\n\nresult = every([5,2,4,1,3], fn(e) { return e \u003e= 2 }); // false\n```\n\nWith this speed, your program's going to finish before you've even started writing it.\n\n### Testimonials\n\nDave says:\n\n\u003e _OK?_ has transformed me from an angry developer to a happy developer. I used to think composition over inheritance, having my own projects composed of various different languages, never thinking about the power of evolution. Now I've evolved to only use one language: _OK?_\n\nJoel says:\n\n\u003e I used to find _OK?_'s opinionated syntax constraints coercive. Now I find them liberating. Thinking hard about how to fit a complex variable name into eight characters forces me to write code that future me can easily maintain\n\nSarah says:\n\n\u003e I used to think there were all these features I needed to write quality software, but after a while working with _OK?_ it just clicked: when you stick to the basics, the resulting code is clear and easy to understand.\n\nJack says:\n\n\u003e If I'm on the _OK?_ subreddit and I see you use the word 'class' when you meant to say 'nac', I'm going to start screaming. And that screaming will not stop until I've found you. By then, you'll be the one screaming.\n\n### How To Get Started\n\nTo play around with the language in your browser, you can go to the [playground](https://www.okquestionmark.org/)\n\nTo use the language locally, follow the following steps:\n\n1. `git clone` the repo.\n2. within the `ok` directory run `go install`.\n3. Run `ok` without any arguments to bring up the REPL, or you can run an _OK?_ file with `ok test.ok`.\n\nHappy OK'ing!\n\n### Credits\n\n- Thanks to https://interpreterbook.com/ for helping us create the best new language since assembly\n- Thanks to @markbergin77 for the idea about nulls not being OK\n- Thanks to @matomatical for showing that even two comparison operators was one too many.\n- Thanks to Rob for vectorising Quentyn\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjesseduffield%2Fok","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjesseduffield%2Fok","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjesseduffield%2Fok/lists"}