Movatterモバイル変換


[0]ホーム

URL:


Skip to content
DEV Community
Log in Create account

DEV Community

Kei Kamikawa
Kei Kamikawa

Posted on

     

Some tips and bothers for Go 1.18 Generics

As of 2021-11-17, there is probably no cache library that uses the Go 1.18 Generics feature.

I've tried to implement the first Go 1.18 generics cache library here. I'm very happy if you give me a GitHub star.

https://github.com/Code-Hex/go-generics-cache

In this article, I'll introduce some of the things I noticed about Go Generics while developing this cache library, as well as some of the tips and bothers I found.

Return zero value for any type

You will often write code that returns any and error, such as the following. When an error occurs in a function, you would have written code that returns zero-value and error, but now you need to think a little bit differently.

funcDo[Vany](vV)(V,error){iferr:=validate(v);err!=nil{// What should we return here?}returnv,nil}funcvalidate[Vany](vV)error
Enter fullscreen modeExit fullscreen mode

Let’s suppose you writereturn 0, err here. This will be a compilation error. The reason is thatany type can be a type other thanint type, such asstring type. So how do we do this?

Let's declare a variable once usingV of the type parameter. Then you can write it in a compilable form as follows.

funcDo[Vany](vV)(V,error){varretViferr:=validate(v);err!=nil{returnret,err}returnv,nil}
Enter fullscreen modeExit fullscreen mode

In addition, named return values can be used to simplify the writing for a single line.

funcDo[Vany](vV)(retV,_error){iferr:=validate(v);err!=nil{returnret,err}returnv,nil}
Enter fullscreen modeExit fullscreen mode

https://gotipplay.golang.org/p/0UqA0PIO9X8

Don't try to do type switch withconstraints

I wanted to provide two methods,Increment andDecrement. They can add or subtract values from thego-generics-cache library if the stored value satisfies theNumber constraint.

Let's useIncrement method as an example. I initially wrote code like this.

typeCache[Kcomparable,Vany]struct{itemsmap[K]V}func(c*Cache[K,V])Increment(kK,nV)(valV,_error){got,ok:=c.items[k]if!ok{returnval,errors.New("not found")}switch(interface{})(n).(type){caseNumber:nv:=got+nc.items[k]=nvreturnnv,nil}returnval,nil}
Enter fullscreen modeExit fullscreen mode

I was thinking of using the type of the valuen V to match the constraints that are satisfied. This method that adds if theNumber constraint is satisfied, and does nothing otherwise.

This will not compile.

  1. Go does not provide conditional branching for constraints.
  2. constraints is an interface. Go does not allow type assertions using interface.
  3. The type ofn is not determined, so+ operation is not possible.
  4. In the first place, there is no guarantee thatitems type is the same type asn.

To solve this problem, I redesigned the interface. Why did I want to create methods in theCache struct?

  • To inherit the data of the fields held by theCache struct.
  • To handle methods of theCache.

To solve these points, I decided to embed theCache struct. And I defined aNumberCache struct that can always handleNumber constraints.

typeNumberCache[Kcomparable,VNumber]struct{*Cache[K,V]}
Enter fullscreen modeExit fullscreen mode

This way, we can guarantee that the type of the value passed to theCache struct will always be aNumber constraint. So we can add anIncrement method toNumberCache struct.

func(c*NumberCache[K,V])Increment(kK,nV)(valV,_error){got,ok:=c.Cache.items[k]if!ok{returnval,errors.New("not found")}nv:=got+nc.Cache.items[k]=nvreturnval,nil}
Enter fullscreen modeExit fullscreen mode

https://gotipplay.golang.org/p/poQeWw4UE_L

The point of bothered me

Let's look at the definition of theCache struct again.

typeCache[Kcomparable,Vany]struct{itemsmap[K]V}
Enter fullscreen modeExit fullscreen mode

Go Generics is defined as a language specification with a constraint which is calledcomparable. Which allows only types can use== and!=.

I feel that this constraint is bothered me. Let’s explain the reasons why bother me.

I defined a function that compares twocomparable values.

funcEqual[Tcomparable](v1,v2T)bool{returnv1==v2}
Enter fullscreen modeExit fullscreen mode

Allowing onlycomparable types are going to result in an error if an incomparable type is passed to the function at compile-time. You may think this is useful.

However, according to Go's specification,interface{} also satisfies thiscomparable constraint.

Ifinterface{} can be satisfied, the following code can be compiled.

funcmain(){v1:=interface{}(func(){})v2:=interface{}(func(){})Equal(v1,v2)}
Enter fullscreen modeExit fullscreen mode

This shows thatfunc() type which is a non-comparable type. but can be converting as a comparable type by casting it to theinterface{} type.

interface{} type will only know at runtime whether it is a comparable type or not.

If this is a complex code, it may be difficult to notice.

https://gotipplay.golang.org/p/tbKKuehbzUv

I believe that we need another comparable constraints that do not acceptinterface{} to notice at compile-time.

Can this constraints be defined by Go users? The answer is currently not.

This is becausecomparable constraint contains "comparable structures" and "comparable arrays". These constraints cannot currently be defined by Go users. Therefore, I would like to provide them as a Go specification.

I also created a proposal for it, so if you can relate to it, I would appreciate it if you could give me 👍 in GitHub issue.

https://github.com/golang/go/issues/49587

Top comments(0)

Subscribe
pic
Create template

Templates let you quickly answer FAQs or store snippets for re-use.

Dismiss

Are you sure you want to hide this comment? It will become hidden in your post, but will still be visible via the comment'spermalink.

For further actions, you may consider blocking this person and/orreporting abuse

  • Location
    Japan
  • Work
    codehex at Tokyo
  • Joined

Trending onDEV CommunityHot

DEV Community

We're a place where coders share, stay up-to-date and grow their careers.

Log in Create account

[8]ページ先頭

©2009-2025 Movatter.jp