Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up

An experimental implementation of 'try' operator for Go

License

NotificationsYou must be signed in to change notification settings

rhysd/trygo

Repository files navigation

This is a translator of 'TryGo' as my experiment to see what happens if Go were havingtry() function.Basic idea oftry() came from Rust'stry! macro (or? operator).try() handlesif err != nilcheck implicitly.

This package provides a code translator from TryGo (Go withtry()) to Go.

Go:

funcCreateFileInSubdir(subdir,filenamestring,content []byte)error {cwd,err:=os.Getwd()iferr!=nil {returnerr    }iferr:=os.Mkdir(filepath.Join(cwd,subdir));err!=nil {returnerr    }p:=filepath.Join(cwd,subdir,filename)f,err:=os.Create(p)iferr!=nil {returnerr    }deferf.Close()if_,err:=f.Write(content);err!=nil {returnerr    }fmt.Println("Created:",p)returnnil}

TryGo:

funcCreateFileInSubdir(subdir,filenamestring,content []byte)error {cwd:=try(os.Getwd())try(os.Mkdir(filepath.Join(cwd,subdir)))p:=filepath.Join(cwd,subdir,filename)f:=try(os.Create(p))deferf.Close()try(f.Write(content))fmt.Println("Created:",p)returnnil}

There is only one difference between Go and TryGo. Special magic functiontry() is provided in TryGo.

Spec

try looks function, but actually it is a special operator. It has variadic parameters and variadicreturn values. In terms of Go,try looks like:

func try(ret... interface{}, err error) (... interface{})

Actuallytry() is a set of macros which takes one function call and expands it to a code with errorcheck. It takes one function call as argument since Go only allows multiple values as return valuesof function call.

In following subsections,$zerovals is expanded to zero-values of return values of the function.For example, whentry() is used infunc () (int, error),$zerovals will be0. When it is usedinfunc () (*SomeStruct, SomeInterface, SomeStruct, error),$zerovals will benil, nil, SomeStruct{}.

Implementation:

  • Definition statement
  • Assignment statement
  • Call statement
  • Call Expression

Definition statement

$Vars := try($CallExpr)var $Vars = try($CallExpr)

Expanded to:

$Vars, err := $CallExprif err != nil {    return $zerovals, err}var $Vars, err = $CallExprif err != nil {    return $zerovals, err}

Assignment statement

$Assignee = try($CallExpr)

Expanded to:

var err error$Assignee, err = $CallExprif err != nil {    return $zerovals, err}

Assignment operationx op= y (e.g.x += y) is supported.

$Assignee op= try($CallExpr)

Expanded to:

$tmp, err := $CallExprif err != nil {    return $zerovals, err}$Assignee op= $tmp

Call statement

try($CallExpr)

Expanded to:

if $underscores, err := $CallExpr; err != nil {    return err}

$underscores, is a set of_s which ignores all return values from$CallExpr. For example, whencallingfunc() (int, error), it is expanded to_. When callingfunc() (A, B, error) intry(),it is expanded to_, _. When callingfunc() error intry(), it is expanded to an empty.

Call Expression

try() call except for toplevel in block

1 + try($CallExpr)

Expanded to:

$tmp, err := $CallExprif err != nil {    return $zerovals, err}1 + $tmp

This should allow nest. For example,

1 + try(Foo(try($CallExpr), arg))
$tmp1, err := $CallExprif err != nil {    return $zerovals, err}$tmp2, err := Foo($tmp1, arg)if err != nil {    return $zerovals, err}1 + $tmp2

The order of evaluation must be preserved. For example, whentry() is used in a slice literal element,elements before the element must be calculated before theif err != nil check of thetry().

For example,

ss := []string{"aaa", s1 + "x", try(f()), s2[:n]}

will be translated to

tmp1 := "aaa"tmp2 := s1 + "x"tmp3, err := f()if err != nil {    return $zerovals, err}ss := []string{tmp1, tmp2, tmp3, s2[:n]}

Ill-formed cases

  • try() cannot take other than function call. For example,try(42) is ill-formed.
  • try() is expanded to code includingreturn. Using it outside functions is ill-formed.
  • When function called intry() invocation does not returnerror as last of return values, it is ill-formed.

These ill-formed code should be detected by translator and it will raise an error.

Whytry() 'function'? Why not? operator?

Following code may look even better. At least I think so.

funcCreateFile(subdir,filenamestring,content []byte)error {cwd:=os.Getwd()?    os.Mkdir(filepath.Join(cwd,subdir))?f:= os.Create(filepath.Join(cwd,subdir,filename))?deferf.Close()    f.Write(content)?returnnil}

The reason why I adoptedtry() function is that ...TODO

Installation

Download an executable binary fromrelease page (NOT YET).

To build from source:

$ go get -u github.com/rhysd/trygo/cmd/trygo

Usage

$ trygo -o {outpath} {inpaths}

{inpaths} is a list of directory paths of Go packages you want to translate. The directories aretranslated recursively. For example, whendir is passed and there are 2 packagesdir anddir/nested,both packages will be translated.

{outpath} is a directory path where translated Go packages are put. For example, whendir is specifiedas{inpaths} andout is specified as{outpath},dir/** packages are translated asout/dir/**.

License

MIT License

About

An experimental implementation of 'try' operator for Go

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

[8]ページ先頭

©2009-2025 Movatter.jp