{"id":15387288,"url":"https://github.com/rhysd/trygo","last_synced_at":"2025-04-15T20:15:13.056Z","repository":{"id":66059681,"uuid":"158423243","full_name":"rhysd/trygo","owner":"rhysd","description":"An experimental implementation of 'try' operator for Go","archived":false,"fork":false,"pushed_at":"2019-06-13T22:06:03.000Z","size":96,"stargazers_count":12,"open_issues_count":0,"forks_count":1,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-04-15T20:15:06.490Z","etag":null,"topics":["go","golang","transpile","try"],"latest_commit_sha":null,"homepage":"","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/rhysd.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","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-11-20T16:56:47.000Z","updated_at":"2025-02-06T14:33:43.000Z","dependencies_parsed_at":null,"dependency_job_id":"5933a81f-3acf-4349-ac50-53ee66825628","html_url":"https://github.com/rhysd/trygo","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/rhysd%2Ftrygo","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rhysd%2Ftrygo/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rhysd%2Ftrygo/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rhysd%2Ftrygo/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rhysd","download_url":"https://codeload.github.com/rhysd/trygo/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":249145420,"owners_count":21219966,"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":["go","golang","transpile","try"],"created_at":"2024-10-01T14:53:27.347Z","updated_at":"2025-04-15T20:15:13.038Z","avatar_url":"https://github.com/rhysd.png","language":"Go","readme":"TryGo: Go with 'try' operator\n=============================\n\nThis is a translator of 'TryGo' as my experiment to see what happens if Go were having `try()` function.\nBasic idea of `try()` came from Rust's `try!` macro (or `?` operator). `try()` handles `if err != nil`\ncheck implicitly.\n\nThis package provides a code translator from TryGo (Go with `try()`) to Go.\n\nGo:\n\n```go\nfunc CreateFileInSubdir(subdir, filename string, content []byte) error {\n    cwd, err := os.Getwd()\n    if err != nil {\n        return err\n    }\n\n    if err := os.Mkdir(filepath.Join(cwd, subdir)); err != nil {\n        return err\n    }\n\n    p := filepath.Join(cwd, subdir, filename)\n    f, err := os.Create(p)\n    if err != nil {\n        return err\n    }\n    defer f.Close()\n\n    if _, err := f.Write(content); err != nil {\n        return err\n    }\n\n    fmt.Println(\"Created:\", p)\n    return nil\n}\n```\n\nTryGo:\n\n```go\nfunc CreateFileInSubdir(subdir, filename string, content []byte) error {\n    cwd := try(os.Getwd())\n\n    try(os.Mkdir(filepath.Join(cwd, subdir)))\n\n    p := filepath.Join(cwd, subdir, filename)\n    f := try(os.Create(p))\n    defer f.Close()\n\n    try(f.Write(content))\n\n    fmt.Println(\"Created:\", p)\n    return nil\n}\n```\n\nThere is only one difference between Go and TryGo. Special magic function `try()` is provided in TryGo.\n\n\n\n## Spec\n\n`try` looks function, but actually it is a special operator. It has variadic parameters and variadic\nreturn values. In terms of Go, `try` looks like:\n\n```\nfunc try(ret... interface{}, err error) (... interface{})\n```\n\nActually `try()` is a set of macros which takes one function call and expands it to a code with error\ncheck. It takes one function call as argument since Go only allows multiple values as return values\nof function call.\n\nIn following subsections, `$zerovals` is expanded to zero-values of return values of the function.\nFor example, when `try()` is used in `func () (int, error)`, `$zerovals` will be `0`. When it is used\nin `func () (*SomeStruct, SomeInterface, SomeStruct, error)`, `$zerovals` will be `nil, nil, SomeStruct{}`.\n\nImplementation:\n- [x] Definition statement\n- [x] Assignment statement\n- [x] Call statement\n- [ ] Call Expression\n\n### Definition statement\n\n```\n$Vars := try($CallExpr)\n\nvar $Vars = try($CallExpr)\n```\n\nExpanded to:\n\n```\n$Vars, err := $CallExpr\nif err != nil {\n    return $zerovals, err\n}\n\nvar $Vars, err = $CallExpr\nif err != nil {\n    return $zerovals, err\n}\n```\n\n### Assignment statement\n\n```\n$Assignee = try($CallExpr)\n```\n\nExpanded to:\n\n```\nvar err error\n$Assignee, err = $CallExpr\nif err != nil {\n    return $zerovals, err\n}\n```\n\nAssignment operation `x op= y` (e.g. `x += y`) is supported.\n\n```\n$Assignee op= try($CallExpr)\n```\n\nExpanded to:\n\n```\n$tmp, err := $CallExpr\nif err != nil {\n    return $zerovals, err\n}\n$Assignee op= $tmp\n```\n\n### Call statement\n\n```\ntry($CallExpr)\n```\n\nExpanded to:\n\n```\nif $underscores, err := $CallExpr; err != nil {\n    return err\n}\n```\n\n`$underscores,` is a set of `_`s which ignores all return values from `$CallExpr`. For example, when\ncalling `func() (int, error)`, it is expanded to `_`. When calling `func() (A, B, error)` in `try()`,\nit is expanded to `_, _`. When calling `func() error` in `try()`, it is expanded to an empty.\n\n### Call Expression\n\n`try()` call except for toplevel in block\n\n```\n1 + try($CallExpr)\n```\n\nExpanded to:\n\n```\n$tmp, err := $CallExpr\nif err != nil {\n    return $zerovals, err\n}\n1 + $tmp\n```\n\nThis should allow nest. For example,\n\n```\n1 + try(Foo(try($CallExpr), arg))\n```\n\n```\n$tmp1, err := $CallExpr\nif err != nil {\n    return $zerovals, err\n}\n$tmp2, err := Foo($tmp1, arg)\nif err != nil {\n    return $zerovals, err\n}\n1 + $tmp2\n```\n\nThe order of evaluation must be preserved. For example, when `try()` is used in a slice literal element,\nelements before the element must be calculated before the `if err != nil` check of the `try()`.\n\nFor example,\n\n```\nss := []string{\"aaa\", s1 + \"x\", try(f()), s2[:n]}\n```\n\nwill be translated to\n\n```\ntmp1 := \"aaa\"\ntmp2 := s1 + \"x\"\ntmp3, err := f()\nif err != nil {\n    return $zerovals, err\n}\nss := []string{tmp1, tmp2, tmp3, s2[:n]}\n```\n\n### Ill-formed cases\n\n- `try()` cannot take other than function call. For example, `try(42)` is ill-formed.\n- `try()` is expanded to code including `return`. Using it outside functions is ill-formed.\n- When function called in `try()` invocation does not return `error` as last of return values, it is ill-formed.\n\nThese ill-formed code should be detected by translator and it will raise an error.\n\n\n\n## Why `try()` 'function'? Why not `?` operator?\n\nFollowing code may look even better. At least I think so.\n\n```go\nfunc CreateFile(subdir, filename string, content []byte) error {\n    cwd := os.Getwd()?\n    os.Mkdir(filepath.Join(cwd, subdir))?\n    f := os.Create(filepath.Join(cwd, subdir, filename))?\n    defer f.Close()\n    f.Write(content)?\n    return nil\n}\n```\n\nThe reason why I adopted `try()` function is that ...TODO\n\n## Installation\n\nDownload an executable binary from [release page](https://github.com/rhysd/trygo/releases) (NOT YET).\n\nTo build from source:\n\n```\n$ go get -u github.com/rhysd/trygo/cmd/trygo\n```\n\n\n\n## Usage\n\n```\n$ trygo -o {outpath} {inpaths}\n```\n\n`{inpaths}` is a list of directory paths of Go packages you want to translate. The directories are\ntranslated recursively. For example, when `dir` is passed and there are 2 packages `dir` and `dir/nested`,\nboth packages will be translated.\n\n`{outpath}` is a directory path where translated Go packages are put. For example, when `dir` is specified\nas `{inpaths}` and `out` is specified as `{outpath}`, `dir/**` packages are translated as `out/dir/**`.\n\n\n\n## License\n\n[MIT License](LICENSE.txt)\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frhysd%2Ftrygo","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frhysd%2Ftrygo","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frhysd%2Ftrygo/lists"}