{"id":13307303,"url":"https://github.com/RealyUniqueName/Safety","last_synced_at":"2025-03-10T15:32:45.815Z","repository":{"id":151066946,"uuid":"117523648","full_name":"RealyUniqueName/Safety","owner":"RealyUniqueName","description":"Null safety for Haxe","archived":false,"fork":false,"pushed_at":"2021-02-24T14:07:52.000Z","size":2278,"stargazers_count":54,"open_issues_count":3,"forks_count":5,"subscribers_count":14,"default_branch":"master","last_synced_at":"2025-02-16T17:56:15.028Z","etag":null,"topics":["haxe","haxe-plugin","null-safety","safe-navigation"],"latest_commit_sha":null,"homepage":"","language":"Haxe","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/RealyUniqueName.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":"2018-01-15T09:18:38.000Z","updated_at":"2024-09-25T16:36:39.000Z","dependencies_parsed_at":null,"dependency_job_id":"d58ad469-da39-4e7b-b559-2ced699ef917","html_url":"https://github.com/RealyUniqueName/Safety","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/RealyUniqueName%2FSafety","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RealyUniqueName%2FSafety/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RealyUniqueName%2FSafety/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RealyUniqueName%2FSafety/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/RealyUniqueName","download_url":"https://codeload.github.com/RealyUniqueName/Safety/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":242876855,"owners_count":20199910,"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":["haxe","haxe-plugin","null-safety","safe-navigation"],"created_at":"2024-07-29T18:00:16.127Z","updated_at":"2025-03-10T15:32:45.786Z","avatar_url":"https://github.com/RealyUniqueName.png","language":"Haxe","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Safety [![Build Status](https://travis-ci.org/RealyUniqueName/Safety.svg?branch=master)](https://travis-ci.org/RealyUniqueName/Safety)\n\nThis library implements a few features for writing Haxe code which generates less null pointer errors. These features are: static extensions for more enjoyable null safety, safe navigation operator, safe arrays, safe api (automatic checks of method arguments for `null`).\n\n## Installation\n\nHaxe 4 is required.\n\nInstall Safety from haxelib:\n```\nhaxelib install safety\n```\nor the latest development version from github:\n```\nhaxelib git safety https://github.com/RealyUniqueName/Safety.git\n```\n\n## Usage\n\nAdd `-lib safety` to your hxml file.\nUse following compiler arguments:\n\n* `--macro Safety.safeNavigation(dotPath, recursive)` - Enables [safe navigation operator](https://en.wikipedia.org/wiki/Safe_navigation_operator) `!.` in the specified path. If `recursive` is `true` (it is by default), then `!.` operator is also enabled for subpackages in `dotPath`.\n* `--macro Safety.safeArray(dotPath, recursive)` - Makes all array declarations to be typed as `SafeArray`. See [feature description](#safe-array) for details.\n* `--macro Safety.safeApi(dotPath, recursive)` - Adds runtime checking for not-nullable arguments of public methods in the specified path. If `null` is passed to such an argument, then `safety.IllegalArgumentException` is thrown. [Details](#safe-api)\n\nAll `--macro Safety.*` arguments can be used multiple times with different `dotPath` values.\n\nYou can pass empty string `\"\"` as any `dotPath` to apply a feature to the whole codebase (not recommended, because a lot of compilation errors will come from std lib).\n\n## Features\n\n### Static extensions for null safety\n\nUsage example:\n```haxe\nusing Safety;\n\nvar nullable:Null\u003cString\u003e = getSomeStr();\nvar s:String = nullable.or('hello');\n```\nAvailable extensions:\n```haxe\n/**\n*  Returns `value` if it is not `null`. Otherwise returns `defaultValue`.\n*/\nstatic public inline function or\u003cT\u003e(value:Null\u003cT\u003e, defaultValue:T):T;\n/**\n*  Returns `value` if it is not `null`.  calls `getter` and returns the result.\n*/\nstatic public inline function orGet\u003cT\u003e(value:Null\u003cT\u003e, getter:Void-\u003eT):T;\n/**\n*  Returns `value` if it is not `null`. Otherwise throws an exception.\n*  @throws safety.NullPointerException if `value` is `null`.\n*/\nstatic public inline function sure\u003cT\u003e(value:Null\u003cT\u003e):T;\n/**\n*  Just returns `value` without any checks, but typed as not-nullable. Use at your own risk.\n*/\nstatic public inline function unsafe\u003cT\u003e(value:Null\u003cT\u003e):T;\n/**\n*  Returns `true` if value is not null and `callback(value)` is evaluated to `true`.\n*  Returns `false` otherwise.\n*/\nstatic public inline function check\u003cT\u003e(value:Null\u003cT\u003e, callback:T-\u003eBool):Bool\n/**\n*  Applies `callback` to `value` and returns the result if `value` is not `null`.\n*  Returns `null` otherwise.\n*/\nstatic public inline function let\u003cT,V\u003e(value:Null\u003cT\u003e, callback:T-\u003eV):Null\u003cV\u003e;\n/**\n*  Passes `value` to `callback` if `value` is not null.\n*/\nstatic public inline function run\u003cT\u003e(value:Null\u003cT\u003e, callback:T-\u003eVoid):Void;\n/**\n*  Applies `callback` to `value` if `value` is not `null`.\n*  Returns `value`.\n*/\nstatic public inline function apply\u003cT\u003e(value:Null\u003cT\u003e, callback:T-\u003eVoid):Null\u003cT\u003e;\n```\n\n### Safe navigation operator\n\nAdds safe navigation operator `!.` to Haxe syntax. Compiler argument to enable it: `--macro Safety.safeNavigation(my.pack)`\n\n```haxe\nvar obj:Null\u003c{ field:Null\u003cString\u003e }\u003e = null;\ntrace(obj!.field!.length); //null\nobj = { field:'hello' };\ntrace(obj!.field!.length); //5\n```\n\n### Safe array\n\n`SafeArray\u003cT\u003e` (abstract over `Array\u003cT\u003e`) behaves exactly like `Array\u003cT\u003e` except it prevents out-of-bounds reading/writing (throws `safety.OutOfBoundsException`). Writing at an index of array's length is allowed.\n\nSee [Null safety limitations](#null-safety-limitations) to find out why you need it.\n\nIf `--macro Safety.safeArray(my.pack)` is in effect, then all array declarations become `SafeArray`:\n```haxe\nvar a = ['hello', 'world'];\n$type(a); //SafeArray\u003cString\u003e\n```\nYou can use `stdArray()` method to get a reference to the `Array\u003cT\u003e`:\n```haxe\nvar a = ['hello', 'world'];\n$type(a.stdArray()); //Array\u003cString\u003e\n```\n\n### Safe api\n\nCompiler argument to enable this feature: `--macro Safety.safeApi(my.pack)`.\n\nIf enabled it adds runtime checking against `null` for all not-nullable arguments of public methods:\n```haxe\npublic function method(arg:String) {}\n\u003c...\u003e\nmethod(null); //throws safety.IllegalArgumentException\n```\nIt's pretty cheap performance wise, because it just adds a simple line to the body of a method: `if(arg == null) throw new IllegalArgumentException();`\n\nIf argument is nullable, no check is generated.\n\nAlso safe api does not generate such checks for `Int`, `Float`, `Bool` (and other basic types) on static targets, because it's impossible to assign `null` to such types on static targets.\n\nThis feature is especially useful if you are creating a library, and you don't want your users to pass `null`s to your API. You can add `--macro Safety.safeApi('my.lib')` to `extraParams.hxml`.\n\n## Null safety Limitations\n\n* Out-of-bounds array read returns `null`, but Haxe types it without `Null\u003c\u003e`. ([PR to the compiler to fix this issue](https://github.com/HaxeFoundation/haxe/pull/6825))\n```haxe\nvar a:Array\u003cString\u003e = [\"hello\"];\n$type(a[100]); // String\ntrace(a[100]); // null\nvar s:String = a[100]; // null-safety does not complain here, because `a[100]` is not `Null\u003cString\u003e`, but just `String`\n```\n* Out-of-bounds array write fills all positions between the last defined index and the newly written one with `null`. null-safety cannot save you in this case.\n```haxe\nvar a:Array\u003cString\u003e = [\"hello\"];\na[2] = \"world\";\ntrace(a); //[\"hello\", null, \"world\"]\nvar s:String = a[1]; //null-safety cannot check this\ntrace(s); //null\n```\n* Haxe was not designed with null safety in mind, so it's always possible `null` will come to your code from 3rd-party code or even from std lib.\n* Nullable fields and properties are not considered null-safe even after checking against `null`. Use safety extensions instead:\n```haxe\nusing Safety;\n\nclass Main {\n    var nullable:Null\u003cString\u003e;\n    function new() {\n        var str:String;\n        if(nullable != null) {\n            str = nullable; //Compilation error.\n        }\n        str = nullable.sure();\n        str = nullable.or('hello');\n    }\n}\n```","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FRealyUniqueName%2FSafety","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FRealyUniqueName%2FSafety","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FRealyUniqueName%2FSafety/lists"}