Last active
April 9, 2017 15:36
-
-
Save rhysd/0dbd94544862cd0f9deea72dbfa38389 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"fmt" | |
"strings" | |
"testing" | |
) | |
// Version A (traditional) | |
type Node interface { | |
String() string | |
} | |
type Constant struct { | |
Value int | |
} | |
func (c *Constant) String() string { | |
return fmt.Sprintf("%d", c.Value) | |
} | |
type BinOp struct { | |
Left Expr | |
Right Expr | |
} | |
func (o *BinOp) String() string { | |
return fmt.Sprintf("%s + %s", o.Left.String(), o.Right.String()) | |
} | |
type Sequence struct { | |
Exprs []Expr | |
} | |
func (o *Sequence) String() string { | |
ss := make([]string, 0, len(o.Exprs)) | |
for _, e := range o.Exprs { | |
ss = append(ss, e.String()) | |
} | |
return strings.Join(ss, ";") | |
} | |
type Expr interface { | |
Node | |
exprNode() | |
} | |
func (e *BinOp) exprNode() {} | |
func (e *Constant) exprNode() {} | |
func Check(n Node) string { | |
switch n := n.(type) { | |
case Expr: | |
return "Expression: " + n.String() | |
default: | |
return "Not an expression: " + n.String() | |
} | |
} | |
func BenchmarkTypeA(b *testing.B) { | |
for i := 0; i < b.N; i++ { | |
nodes := []Node{ | |
&Constant{42}, | |
&BinOp{&Constant{42}, &BinOp{&Constant{1}, &Constant{0}}}, | |
&Sequence{[]Expr{}}, | |
&Sequence{[]Expr{&Constant{42}, &Constant{1}, &Constant{0}}}, | |
&Sequence{[]Expr{&BinOp{&Constant{42}, &BinOp{&Constant{1}, &Constant{0}}}}}, | |
&BinOp{&Constant{42}, &BinOp{&Constant{1}, &Constant{0}}}, | |
} | |
for _, n := range nodes { | |
Check(n) | |
} | |
} | |
} | |
// Version B (new) | |
type Node2 interface { | |
String() string | |
} | |
type Expr2 interface { | |
Node2 | |
exprNode() | |
} | |
type Constant2 struct { | |
Expr2 | |
Value int | |
} | |
func (c *Constant2) String() string { | |
return fmt.Sprintf("%d", c.Value) | |
} | |
type BinOp2 struct { | |
Expr2 | |
Left Expr2 | |
Right Expr2 | |
} | |
func (o *BinOp2) String() string { | |
return fmt.Sprintf("%s + %s", o.Left.String(), o.Right.String()) | |
} | |
type Sequence2 struct { | |
Exprs []Expr2 | |
} | |
func (o *Sequence2) String() string { | |
ss := make([]string, 0, len(o.Exprs)) | |
for _, e := range o.Exprs { | |
ss = append(ss, e.String()) | |
} | |
return strings.Join(ss, ";") | |
} | |
func Check2(n Node2) string { | |
switch n := n.(type) { | |
case Expr2: | |
return "Expression: " + n.String() | |
default: | |
return "Not an expression: " + n.String() | |
} | |
} | |
func BenchmarkTypeB(b *testing.B) { | |
for i := 0; i < b.N; i++ { | |
nodes := []Node2{ | |
&Constant2{Value: 42}, | |
&BinOp2{Left: &Constant2{Value: 42}, Right: &BinOp2{Left: &Constant2{Value: 1}, Right: &Constant2{Value: 0}}}, | |
&Sequence2{[]Expr2{}}, | |
&Sequence2{[]Expr2{&Constant2{Value: 42}, &Constant2{Value: 1}, &Constant2{Value: 0}}}, | |
&Sequence2{[]Expr2{&BinOp2{Left: &Constant2{Value: 42}, Right: &BinOp2{Left: &Constant2{Value: 1}, Right: &Constant2{Value: 0}}}}}, | |
&BinOp2{Left: &Constant2{Value: 42}, Right: &BinOp2{Left: &Constant2{Value: 1}, Right: &Constant2{Value: 0}}}, | |
} | |
for _, n := range nodes { | |
Check2(n) | |
} | |
} | |
} | |
// Baseline | |
type Node3 interface { | |
String() string | |
} | |
type Constant3 struct { | |
Value int | |
} | |
func (c *Constant3) String() string { | |
return fmt.Sprintf("%d", c.Value) | |
} | |
type BinOp3 struct { | |
Left Node3 | |
Right Node3 | |
} | |
func (o *BinOp3) String() string { | |
return fmt.Sprintf("%s + %s", o.Left.String(), o.Right.String()) | |
} | |
type Sequence3 struct { | |
Exprs []Node3 | |
} | |
func (o *Sequence3) String() string { | |
ss := make([]string, 0, len(o.Exprs)) | |
for _, e := range o.Exprs { | |
ss = append(ss, e.String()) | |
} | |
return strings.Join(ss, ";") | |
} | |
func Check3(n Node3) string { | |
switch n := n.(type) { | |
case *Constant3, *BinOp3: | |
return "Expression: " + n.String() | |
default: | |
return "Not an expression: " + n.String() | |
} | |
} | |
func BenchmarkTypeBaseline(b *testing.B) { | |
for i := 0; i < b.N; i++ { | |
nodes := []Node3{ | |
&Constant3{Value: 42}, | |
&BinOp3{Left: &Constant3{Value: 42}, Right: &BinOp3{Left: &Constant3{Value: 1}, Right: &Constant3{Value: 0}}}, | |
&Sequence3{[]Node3{}}, | |
&Sequence3{[]Node3{&Constant3{Value: 42}, &Constant3{Value: 1}, &Constant3{Value: 0}}}, | |
&Sequence3{[]Node3{&BinOp3{Left: &Constant3{Value: 42}, Right: &BinOp3{Left: &Constant3{Value: 1}, Right: &Constant3{Value: 0}}}}}, | |
&BinOp3{Left: &Constant3{Value: 42}, Right: &BinOp3{Left: &Constant3{Value: 1}, Right: &Constant3{Value: 0}}}, | |
} | |
for _, n := range nodes { | |
Check3(n) | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
BenchmarkTypeA-8 500000 3588 ns/op | |
BenchmarkTypeB-8 500000 3813 ns/op | |
BenchmarkTypeBaseline-8 500000 3512 ns/op | |
PASS | |
ok github.com/rhysd/ast-test 5.581s |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment