Lock in $30 Savings on PRO—Offer Ends Soon! ⏳
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Fuzzy generics
Search
Alexey Palazhchenko
February 05, 2022
Programming
0
160
Fuzzy generics
Alexey Palazhchenko
February 05, 2022
Tweet
Share
More Decks by Alexey Palazhchenko
See All by Alexey Palazhchenko
Using PostgreSQL's Background Worker Processes For Fun and Profit
aleksi
0
140
Песнь Хорьков и Гоферов
aleksi
0
360
On Ferrets and Gophers
aleksi
0
250
How to Go Wrong with Concurrency
aleksi
2
770
Adding context to existing code
aleksi
1
150
Зачем и как написать свой database/sql драйвер
aleksi
1
180
Cooking gRPC
aleksi
1
880
Profiling and Optimizing Go Programs
aleksi
1
1.8k
Go: начало
aleksi
0
120
Other Decks in Programming
See All in Programming
251126 TestState APIってなんだっけ?Step Functionsテストどう変わる?
east_takumi
0
320
20 years of Symfony, what's next?
fabpot
2
360
S3 VectorsとStrands Agentsを利用したAgentic RAGシステムの構築
tosuri13
6
310
DSPy Meetup Tokyo #1 - はじめてのDSPy
masahiro_nishimi
1
170
ZOZOにおけるAI活用の現在 ~モバイルアプリ開発でのAI活用状況と事例~
zozotech
PRO
8
5.6k
Socio-Technical Evolution: Growing an Architecture and Its Organization for Fast Flow
cer
PRO
0
330
複数人でのCLI/Infrastructure as Codeの暮らしを良くする
shmokmt
5
2.3k
dotfiles 式年遷宮 令和最新版
masawada
1
770
Context is King? 〜Verifiability時代とコンテキスト設計 / Beyond "Context is King"
rkaga
9
1.2k
開発に寄りそう自動テストの実現
goyoki
2
960
Github Copilotのチャット履歴ビューワーを作りました~WPF、dotnet10もあるよ~ #clrh111
katsuyuzu
0
110
WebRTC、 綺麗に見るか滑らかに見るか
sublimer
1
160
Featured
See All Featured
Stop Working from a Prison Cell
hatefulcrawdad
273
21k
Balancing Empowerment & Direction
lara
5
800
Scaling GitHub
holman
464
140k
The Web Performance Landscape in 2024 [PerfNow 2024]
tammyeverts
12
970
Speed Design
sergeychernyshev
33
1.4k
The World Runs on Bad Software
bkeepers
PRO
72
12k
Writing Fast Ruby
sferik
630
62k
Facilitating Awesome Meetings
lara
57
6.7k
Documentation Writing (for coders)
carmenintech
76
5.2k
The MySQL Ecosystem @ GitHub 2015
samlambert
251
13k
Faster Mobile Websites
deanohume
310
31k
Code Reviewing Like a Champion
maltzj
527
40k
Transcript
Fuzzy generics Several months of using 1.18 features Alexey Palazhchenko
FOSDEM 2022-02-05
None
Why Go 1.18?
Why Go 1.18? Generics
Why Go 1.18? Generics Fuzzing
Why Go 1.18? Generics Fuzzing
Generics
Generics • Generics do not work there; let's go back
to interfaces
Generics • Generics do not work there; let's go back
to interfaces • Let me extract a small example for a talk
Generics • Generics do not work there; let's go back
to interfaces • Let me extract a small example for a talk • Hm, that's not that bad
BSON Document
BSON Document • Ordered map
BSON Document • Ordered map • Keys – string, values
– any BSON value, including other documents
BSON Document • Ordered map • Keys – string, values
– any BSON value, including other documents • The central data structure in FerretDB
Interfaces type BSONType interface { bsontype() // sealed } type
Int int func (Int) bsontype() {} type String string func (String) bsontype() {}
Interfaces type BSONType interface { bsontype() // sealed } type
Int int func (Int) bsontype() {} type String string func (String) bsontype() {} type Document struct { m map[string]BSONType keys []string } func (*Document) bsontype() {}
Interfaces func (d *Document) Set(key String, value BSONType) { if
_, ok := d.m[key]; !ok { d.keys = append(d.keys, key) } d.m[key] = value }
Interfaces d.Set("foo", Int(42))
Interfaces d.Set("foo", Int(42)) d.Set("qux", nil)
Generics type BSONType interface { int | string | *Document
}
Generics type BSONType interface { int | string | *Document
} type Document struct { m map[string]any keys []string }
Generics func (d *Document) Set[T BSONType](key string, value T) {
if _, ok := d.m[key]; !ok { d.keys = append(d.keys, key) } d.m[key] = value }
Generics func (d *Document) Set[T BSONType](key string, value T) {
if _, ok := d.m[key]; !ok { d.keys = append(d.keys, key) } d.m[key] = value } syntax error: method must have no type parameters
Generics func DocumentSet[T BSONType](d *Document, key string, value T) {
if _, ok := d.m[key]; !ok { d.keys = append(d.keys, key) } d.m[key] = value }
Generics DocumentSet(d, "foo", 42)
Generics DocumentSet(d, "foo", 42) // DocumentSet(d, "qux", nil)
Interfaces func MakeDocument(pairs ...BSONType) (*Document, error) { l := len(pairs)
if l%2 != 0 { return nil, fmt.Errorf("%d arguments", l)
Interfaces
Interfaces MakeDocument( String("foo"), Int(42), String("bar"), String("baz"), )
Interfaces MakeDocument( String("foo"), Int(42), String("bar"), String("baz"), ) MakeDocument(String("invalid number of
arguments"))
Interfaces MakeDocument( String("foo"), Int(42), String("bar"), String("baz"), ) MakeDocument(String("invalid number of
arguments")) MakeDocument(Int(42), String("invalid key type"))
Generics
Generics func MakeDocument[T BSONType](key string, value T) *Document
Generics func MakeDocument[T BSONType](key string, value T) *Document func MakeDocument2[T1,
T2 BSONType](key1 string, value1 T1, key2 string, value2 T2) *Document
Generics func MakeDocument[T BSONType](key string, value T) *Document func MakeDocument2[T1,
T2 BSONType](key1 string, value1 T1, key2 string, value2 T2) *Document func MakeDocument3[T1, T2, T3 BSONType](key1 string, value1 T1, key2 string, value2 T2, key3 string, value3 T3) *Document
Interfaces
Interfaces func (d *Document) Get(key String) BSONType { return d.m[key]
}
Interfaces func (d *Document) Get(key String) BSONType { return d.m[key]
} assert.Equal(t, Int(42), d.Get("foo")) assert.Equal(t, nil, d.Get("baz"))
Generics
Generics func DocumentGet[T BSONType](d *Document, key string) T { v,
_ := d.m[key].(T) return v }
Generics func DocumentGet[T BSONType](d *Document, key string) T { v,
_ := d.m[key].(T) return v } assert.Equal(t, 42, DocumentGet[int](d, "foo")) assert.Equal(t, "", DocumentGet[string](d, "foo"))
Generics vs Interfaces
Generics vs Interfaces • Better in some aspects
Generics vs Interfaces • Better in some aspects • Worse
in others
Generics vs Interfaces • Better in some aspects • Worse
in others
Fuzzing
Fuzzing • testing/quick on steroids
Fuzzing • testing/quick on steroids • MongoDB binary protocol parsing
packages
Fuzzing • testing/quick on steroids • MongoDB binary protocol parsing
packages • FerretDB had fuzzing tests even before unit tests
Table-driven tests type testCase struct { name string b []byte
v bsontype err error }
Table-driven tests type testCase struct { name string b []byte
v bsontype err error } • Unmarshal b to (v2, err2) • compare with v or err • Marshal v2 to b2 • compare with b
Table-driven tests func TestDocument(t *testing.T) { for _, tc :=
range testCases { tc := tc t.Run(tc.name, func(t *testing.T) {
Fuzzing func FuzzDocument(f *testing.F) { for _, tc := range
testCases { f.Add(tc.b) } f.Fuzz(func(t *testing.T, b []byte) {
When b2 != b
When b2 != b • b might be larger than
needed
When b2 != b • b might be larger than
needed • The unread portion of b should be removed
When b2 != b • b might be larger than
needed • The unread portion of b should be removed • Some bytes might be insigni fi cant
When b2 != b • b might be larger than
needed • The unread portion of b should be removed • Some bytes might be insigni fi cant • Use canonization (json.Compact, etc)
Fuzzing issues
Fuzzing issues • No subtests (testing.F.Run)
Fuzzing issues • No subtests (testing.F.Run) • Unnamed seed values
Fuzzing issues • No subtests (testing.F.Run) • Unnamed seed values
• Hanging detection is unreliable with unset GOMAXPROCS
Fuzzing
Fuzzing • Found a few bugs in `go test -fuzz`
Fuzzing • Found a few bugs in `go test -fuzz`
• Found many many bugs in FerretDB
Fuzzing • Found a few bugs in `go test -fuzz`
• Found many many bugs in FerretDB • De fi nitely use it for parsing
Links • https://github.com/AlekSi/ generics-vs-interfaces • https://github.com/akutz/ go-generics-the-hard-way • https://go.dev/doc/tutorial/ •
https://go.dev/doc/fuzz/ • https://www.ferretdb.io • https://github.com/FerretDB ⭐ • https://github.com/AlekSi • @paaleksey