Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Generative Programming in Go
Search
monochromegane
June 21, 2015
Technology
7.6k
16
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Generative Programming in Go
GoCon2015発表資料
https://github.com/GoCon/GoCon/blob/master/2015summer.rst
monochromegane
June 21, 2015
More Decks by monochromegane
See All by monochromegane
Go言語とトイモデルで学ぶTransformerの気持ち / fukuokago23-transformer
monochromegane
0
190
適応的スパムフィルタのための軽量な類似メッセージカウンタ / jsai2026-adaptive-spam-filter
monochromegane
0
4.9k
ベクトル検索のフィルタを用いた機械学習モデルとの統合 / python-meetup-fukuoka-06-vector-attr
monochromegane
3
880
Claude Codeセッション現状確認 2026福岡 / fukuoka-aicoding-00-beacon
monochromegane
4
740
Go言語での実装を通して学ぶLLMファインチューニングの仕組み / fukuokago22-llm-peft
monochromegane
0
280
不確実性下における目的と手段の統合的探索に向けた連続腕バンディットの応用 / iot70_gp_rff_mab
monochromegane
2
470
なめらかなシステムと運用維持の終わらぬ未来 / dicomo2025_coherently_fittable_system
monochromegane
0
37k
ベクトル検索システムの気持ち
monochromegane
38
13k
Go言語での実装を通して学ぶ、高速なベクトル検索を支えるクラスタリング技術/fukuokago-kmeans
monochromegane
1
320
Other Decks in Technology
See All in Technology
ソフトウェアサプライチェーンの構造的リスクとコンテナ環境の保護
kyohmizu
5
730
What's new in Go 1.27?
ciarana
0
280
強化学習「理論」入門
enakai00
3
3.6k
LanceDB入門
mocobeta
9
620
TypeScript入門 2026
recruitengineers
PRO
3
740
案件に一番詳しいAIを Amazon Bedrock AgentCore で作る ― 知見が知見を生むチームへ / Compounding Knowledge with AgentCore
yusukeshimizu
1
160
[potatotips #96] Give Your AI Agent the Flutter Playbook
korodroid
0
110
AI・HPC開発を支えるGPU環境の新しい選択肢 液冷GPUシステム「AquSys」の取り組み
gpuunite_official
0
130
SO-101×VLAによる3色キューブのピック&プレース
abeja
0
220
Eight Engineering Unit 紹介資料
sansan33
PRO
3
8.2k
Android skills に学ぶ
kokiko
0
130
Adding Right-to-Left support to your web application with CSS logical properties — Lessons from Redmine
vividtone
0
150
Featured
See All Featured
Redefining SEO in the New Era of Traffic Generation
szymonslowik
1
390
技術選定の審美眼(2025年版) / Understanding the Spiral of Technologies 2025 edition
twada
PRO
120
120k
Chrome DevTools: State of the Union 2024 - Debugging React & Beyond
addyosmani
10
1.3k
Leveraging Curiosity to Care for An Aging Population
cassininazir
1
470
Context Engineering - Making Every Token Count
addyosmani
9
1.1k
Designing Powerful Visuals for Engaging Learning
tmiket
1
500
It's Worth the Effort
3n
188
29k
Writing Fast Ruby
sferik
630
63k
Git: the NoSQL Database
bkeepers
PRO
432
67k
Reality Check: Gamification 10 Years Later
codingconduct
0
2.3k
Build your cross-platform service in a week with App Engine
jlugia
234
19k
Deep Space Network (abreviated)
tonyrice
0
260
Transcript
Generative Programming in Go - GoCon 2015 summer - @monochromegane
MIYAKE Yusuke (@monochromegane)
GMO Pepabo, Inc.
♕ 3 GitHub Awards Go ranking in Japan :)
Generative Programming
ੜతͳ Programming
Generator + Template parse generate Parser Your App Generated Code
AST Code use
Attention, please.
✘ Generics Meta programming Dynamic generation
parse Parser AST Code Go provides
Generator + Template generate Your App Generated Code use We
implement
argen ActiveRecord Generator
GoͰDataMapperͰͳ͘ ActiveRecordϥΠΫʹ DBૢ࡞͢Δ
by Generative programming
ߏମʹ`+AR`ϚʔΧʔΛ͚ͭΔ //+AR type User struct { Id int Name string
Age int }
ੜ͢Δ $ argen main.go $ tree . !"" main.go #""
main_gen.go
ߏମʹARϥΠΫͳϝιου͕ Ճ͞ΕΔ db, _ := sql.Open("sqlite3", "foo.db") Use(db) u :=
User{Name: "test", Age: 20} u.Save() //// INSERT INTO users (name, age) VALUES (?, ?); [test 20] User{}.Where("name", "test").And("age", ">", 20).Query() //// SELECT users.id, users.name, users.age FROM users WHERE name = ? AND age > ?; [test 20]
Generative Programming ͍υίϩ
Case.1 Generics
ҙͷߏମʹڞ௨ͷϝιου Λ࣋ͨͤͭͭɺݸʑͷܕΛѻ͏ var u User u = User{}.First() var h
Hoge h = Hoge{}.First()
ҙͷߏମʹڞ௨ͷϝιου Λ࣋ͨͤͭͭɺݸʑͷܕΛѻ͏ var u User u = User{}.First() var h
Hoge h = Hoge{}.First() • Ωϟετͨ͘͠ͳ͍ • Genericsͷग़൪
ᵆᴸᴸᴸᴸᴸᴸᴸᴸᴸᴸᴸᴸᴸᵪᴸᴸᵊ ᴺwhy no generics golangɹ ᴺݕࡧᴺ ᵎᴸᴸᴸᴸᴸᴸᴸᴸᴸᴸᴸᴸᴸᵲᴸᴸᵒ
Let’s generate !
ߏମʹରͯ͠ݸʑͷܕΛѻ͏ ڞ௨ͷϝιουΛੜ
func (m User) First() (*User, error) { return m.newRelation().First() }
func (r *UserRelation) First() (*User, error) { return r.Order("id", "ASC").Limit(1).QueryRow() } func (r *UserRelation) QueryRow() (*User, error) { row := &User{} err := r.Relation.QueryRow( row.fieldPtrsByName( r.Relation.GetColumns())...) if err != nil { return nil, err } return row, nil }
see also: clipperhouse/gen // +gen slice:"All" type Person struct {
Name string Present bool } gang := PersonSlice { {"Alice", true}, {"Bob", false}, {"Carly", true}, } here := func(p Person) bool { return p.Present } gang.All(here) // => false, Bob didn't make it
Case.2 Performance
ϦϑϨΫγϣϯΛͬͨ൚༻ੑ ύϑΥʔϚϯεͱҾ͖͑ // Useful! but... var u User db.First(&u)
ϕϯνϚʔΫ // read SomeFunc(s.F) SomeFunc(reflect.ValueOf(s).FieldByName("F").Int()) // write s.F = 100
reflect.ValueOf(&s).Elem().FieldByName("F").SetInt(100) $ go test -benchmem -bench . • Mac OSX(10.10.3) • CPU: 2.5GHz Core i5(2Core) • Memory: 8GB • Go: 1.4.2
ߏମϑΟʔϧυʹର͢ΔΞΫηε time Alloced Bytes Allocs read field 0.38 ns 0
B 0 allocs reflect 246 ns 16 B 2 allocs write field 0.36 ns 0 B 0 allocs reflect 199 ns 8 B 1 allocs
ෳͷߏମϑΟʔϧυʹର͢ΔΞΫηε time Alloced Bytes Allocs read field 0.36 ns 0
B 0 allocs reflect 583 ns 88 B 2 allocs write field 0.37 ns 0 B 0 allocs reflect 277 ns 8 B 1 allocs
Let’s generate !
ߏମʹରͯ͠ϑΟʔϧυใ औಘ༻ϝιουΛੜ
func (m *User) fieldValueByName(name string) interface{} { switch name {
case "id", "users.id": return m.Id case "name", "users.name": return m.Name case "age", "users.age": return m.Age default: return "" } } func (m *User) fieldPtrByName(name string) interface{} { switch name { case "id", "users.id": return &m.Id case "name", "users.name": return &m.Name case "age", "users.age": return &m.Age default: return nil } }
see also: pquerna/ffjson //go:generate ffjson $GOFILE type Foo struct {
Bar string } f := Foo{"bar"} b, _ := json.Marshal(f) fmt.Printf("%s\n", string(b)) // => {"Bar":"bar"} https://github.com/pquerna/ffjson
Case.3 DSL
ҙͷߏମͷڞ௨ϝιου هड़༰͕ʹͳΓ͕ͪ // far from the DSL... func (u *User)
BeforeUpdate() (err error) { if u.Name != "abc"{ return fmt.Errorf("%s is invalid name.", u.Name) } if u.Age > 20 { return fmt.Errorf("%d is invalid age.", u.Age) } return nil }
Let’s generate !
ϝιου໊/ίϝϯτ/λά͔Β ఆٛΛิͯ͠ੜ
func (u User) validatesName() ar.Rule { return ar.MakeRule().Format().With("abc").OnCreate() } func
(u User) validatesAge() ar.Rule { return ar.MakeRule().Numericality().OnlyInteger().LessThan(20) } rules := map[string]*ar.Validation{ "name": m.validatesName().Rule(), "age": m.validatesAge().Rule(), } for name, rule := range rules { if ok, errs := ar.NewValidator(rule).On(on).IsValid(m.fieldValueByName(name)); !ok { result = false errors.SetErrors(name, errs) } } >
Case. Bad
ͳΜͰGenerate
• ϝιουͷڞ௨Խɺଟଶੑͷ࣮ݱͳͲߏମͷຒࠐ (ҕৡ)interfaceΛͬͯΔ͖ • http://go-talks.appspot.com/github.com/lestrrat/ go-slides/2014-yapcasia-go-for-perl-mongers/ main.slide#27 • http://blog.monochromegane.com/blog/ 2014/03/23/struct-implementaion-patterns-in-
golang/ • Generate࣮ଆར༻ଆҰख͔͔ؒΔɺෳࡶ ʹͳΓ͕ͪɻGenerateͰΔཧ༝͕આ໌Ͱ͖ͳ͍ͷ Ͱ͋Ε͏͖Ͱͳ͍
Tips
ίϚϯυϥΠϯ/go generate ͷ྆ํʹରԠ͢Δ
from := os.Getenv("GOFILE") if from == "" { if len(args)
> 0 { from = args[0] } else { os.Exit(1) } } $ argen main.go // go:generate argen
defineΛͬͯ templateΛׂཧ͢Δ
{{template "Relation" .}} {{define "Relation"}} type {{.Name}}Relation struct { src
*{{.Name}} *ar.Relation } {{end}} func (t Template) toDefine() string { return fmt.Sprintf("{{define \"%s\"}}%s{{end}}\n", t.Name, t.Text) } var relation = &Template{ Name: "Relation", Text: ` type {{.Name}}Relation struct { src *{{.Name}} *ar.Relation }`
templateͰ ࣗಈܗͱ ΦʔτΠϯϙʔτ
func writeWithFormat(file, template string, structs structs) ([]byte, error) { var
b bytes.Buffer w := bufio.NewWriter(&b) write(w, template, structs) w.Flush() formatted, err := imports.Process(file, b.Bytes(), nil) if err != nil { return nil, err } return formatted, nil } func write(w io.Writer, tplText string, structs structs) error { t := template.New("t") t.Funcs(template.FuncMap{}) tpl := template.Must(t.Parse(tplText)) if err := tpl.Execute(w, structs); err != nil { return err } return nil }
ςετੜʹ ରͯ͠ߦ͏
//go:generate go run ../cmd/argen/main.go package tests import "github.com/monochromegane/argen" //+AR type
User struct { Name string Age int } $ go generate && go test ./...
એ ϖύϘͰΤϯδχΞΛืू͍ͯ͠·͢ɻ ڞʹαʔϏεΛੜΈग़͠ҭͯͯ͘ΕΔ৽͍ؒ͠ Λ͍ͬͯ·͢ɻ http://pepabo.com/recruit/career/engineer/
͓ΘΓ