- Notifications
You must be signed in to change notification settings - Fork1
An experimental implementation of 'try' operator for Go
License
rhysd/trygo
Folders and files
Name | Name | Last commit message | Last commit date | |
---|---|---|---|---|
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 != nil
check 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.
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
$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}
$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
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.
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]}
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 in
try()
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.
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
Download an executable binary fromrelease page (NOT YET).
To build from source:
$ go get -u github.com/rhysd/trygo/cmd/trygo
$ 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/**
.
About
An experimental implementation of 'try' operator for Go
Topics
Resources
License
Uh oh!
There was an error while loading.Please reload this page.
Stars
Watchers
Forks
Releases
Packages0
Uh oh!
There was an error while loading.Please reload this page.