#prog #go #article
What’s New in Go 1.22: slices.Concat
<...>
Early versions of the
The issue goes back to what is called the problem of aliasing. <...> But what if you are concatenating the parts of a slice onto itself? Take this example:
A naïve implementation of
<...>
In the end, it was decided that just always returning a new slice would keep the implementation of
(thanks @golang_for_two)
What’s New in Go 1.22: slices.Concat
<...>
Early versions of the
Concat
proposal included a destination slice argument, like append
. (Concat(dest []T, ss ...[]T) []T
.) Why doesn’t the final version of slices.Concat
have a destination argument to allow users to reuse an existing slice as backing?The issue goes back to what is called the problem of aliasing. <...> But what if you are concatenating the parts of a slice onto itself? Take this example:
s := []int{1, 2, 3, 4}
_ = slices.ConcatWithDestination(s[:0], s[3:4], s[2:3], s[1:2], s[0:1])
// What is s now?
A naïve implementation of
slices.ConcatWithDestination
would clobber the 1 at the start of the slice with 4 before copying it onto the end of the slice, so that you end up with 4, 3, 3, 4 instead of 4, 3, 2, 1 as intended.<...>
In the end, it was decided that just always returning a new slice would keep the implementation of
slices.Concat
simpler and help prevent any issues with accidentally aliasing a slice and getting unexpected results, so the destination slice argument was dropped.(thanks @golang_for_two)
blog.carlana.net
What’s New in Go 1.22: slices.Concat
The backstory on a new function in the slices package of Go 1.22.
#prog #go
6 февраля вышла версия Go 1.22.
Среди прочего в стандартную библиотеку добавлен пакет math/rand/v2. Примечательно это по двум причинам.
Первая: это первый случай, когда в стандартную библиотеку Go добавляют вторую версию пакета. На мой взгляд, это вполне себе довод в пользу того, чтобы не делать std слишком богатой. (Конечно, тут ещё далеко до безобразия Python с urllib3, но кто знает, может, и до этого дойдёт).
Вторая: в proposal на этот пакет упомянуто следующее:
2. Remove Source.Seed, Rand.Seed, and top-level Seed. Top-level Seed is deprecated as of Go 1.20. Source.Seed and Rand.Seed assume that the underlying source can be seeded by a single int64, which is only true of a limited number of sources. Specific source implementations can provide Seed methods with appropriate signatures, or none at all for generators that cannot be reseeded; the details of seeding do not belong in the general interface. [выделение моё]
В оригинальном дизайне rand получение случайных значений действовало через тип
Для сравнения, в растовом rand инициализация из начального значения вынесена в отдельный трейт SeedableRng, где сид определяется через ассоциированный тип.
===========
Другая вещь, которая куда как более стрёмная — это тот факт, что тип
6 февраля вышла версия Go 1.22.
Среди прочего в стандартную библиотеку добавлен пакет math/rand/v2. Примечательно это по двум причинам.
Первая: это первый случай, когда в стандартную библиотеку Go добавляют вторую версию пакета. На мой взгляд, это вполне себе довод в пользу того, чтобы не делать std слишком богатой. (Конечно, тут ещё далеко до безобразия Python с urllib3, но кто знает, может, и до этого дойдёт).
Вторая: в proposal на этот пакет упомянуто следующее:
2. Remove Source.Seed, Rand.Seed, and top-level Seed. Top-level Seed is deprecated as of Go 1.20. Source.Seed and Rand.Seed assume that the underlying source can be seeded by a single int64, which is only true of a limited number of sources. Specific source implementations can provide Seed methods with appropriate signatures, or none at all for generators that cannot be reseeded; the details of seeding do not belong in the general interface. [выделение моё]
В оригинальном дизайне rand получение случайных значений действовало через тип
Rand
, который оборачивал значение, реализующее интерфейс Source
:type Source interface {
Int63() int64
Seed(seed int64)
}
В v2 метод Seed
убрали, а метод Int63
поменяли на Int64
— и совершенно верно, ибо в этом интерфейсе торчали уши конкретной дефолтной реализации Source
. Однако заявление "the details of seeding do not belong in the general interface", как мне кажется, вызвано не общими соображениями, а ограничениями Go. Именно, в идеале у каждого источника случайности должен быть свой тип для сида — но в Go нельзя сделать тип, который является частью интерфейса и который может быть определён реализацией.Для сравнения, в растовом rand инициализация из начального значения вынесена в отдельный трейт SeedableRng, где сид определяется через ассоциированный тип.
===========
Другая вещь, которая куда как более стрёмная — это тот факт, что тип
Rand
может запрашивать данные из Source
только через метод Int64
, а потому остальные методы не могут эксплуатировать тот факт, что они работают с конкретным типом источника случайности, и потому не могут использовать специфичные для этих типов оптимизации. В частности, реализация Rand.Int32
попросту зовёт Int64
на внутреннем Source
и делает битовый сдвиг, отбрасывая младшие 33 бита. Если Rand.Int32
вызывается в цикле, то выходит, что где-то половина работы источника случайности уходит в никуда.go.dev
Go 1.22 is released! - The Go Programming Language
Go 1.22 enhances for loops, brings new standard library functionality and improves performance.
#prog #go #article
Hiring Challenge: Smallest Golang Websocket Client
TL;DR: если опуститься до голых сисколов, выкинуть GC, пошаманить с линкером для выкидывания лишних секций и компилировать под 32 бита, то можно уменьшить размер на четыре порядка по сравнению с бейзлайном.
Занятно, что избавление от std уменьшает размер вдвое по сравнению с предыдущим шагом. gc слаб в LTO?
(thanks @go_perf)
Hiring Challenge: Smallest Golang Websocket Client
TL;DR: если опуститься до голых сисколов, выкинуть GC, пошаманить с линкером для выкидывания лишних секций и компилировать под 32 бита, то можно уменьшить размер на четыре порядка по сравнению с бейзлайном.
Занятно, что избавление от std уменьшает размер вдвое по сравнению с предыдущим шагом. gc слаб в LTO?
(thanks @go_perf)
Dyte
Hiring Challenge: Smallest golang Websocket Client
Learn to create a compact Go program for a websocket server, optimizing the binary size. Insights from a Dyte hiring challenge.
#prog #go #article
Go channels are bad and you should feel bad
Статья из 2016 года, поэтому претензии касательно отсутствия дженериков не применимы, а некоторые утверждения касательно устройства стандартной библиотеки могли устареть.
In all of my Go code I work with, I can count on one hand the number of times channels were really the best choice. Sometimes they are. That’s great! Use them then. But otherwise just stop.
Go channels are bad and you should feel bad
Статья из 2016 года, поэтому претензии касательно отсутствия дженериков не применимы, а некоторые утверждения касательно устройства стандартной библиотеки могли устареть.
In all of my Go code I work with, I can count on one hand the number of times channels were really the best choice. Sometimes they are. That’s great! Use them then. But otherwise just stop.
Jtolio
Go channels are bad and you should feel bad | jtolio.com
#prog #go #article
Golang is not a good language
And its creators don't think you're a good developer.
(17.10.2021)
A month or two ago, I put an image of a tierlist of languages that I like using in my Github readme, ranked from F to S tier. F being my least favorite, and S being my favorite.
<...>
But gophers were FURIOUS that their favorite language was the only one at F tier and demanded an explanation from me, pressing a metaphorical knife to my throat.
So let me explain what I have against Go. Also, just as a disclaimer, I don’t like hating on languages too much. Most of them just want to be tools and have their own shortcomings. But a lot of problems Go experiences seem to be self-imposed restrictions through an ideology that wilfully ignores decades of important language research, which just doesn’t make sense to me.
Golang is not a good language
And its creators don't think you're a good developer.
(17.10.2021)
A month or two ago, I put an image of a tierlist of languages that I like using in my Github readme, ranked from F to S tier. F being my least favorite, and S being my favorite.
<...>
But gophers were FURIOUS that their favorite language was the only one at F tier and demanded an explanation from me, pressing a metaphorical knife to my throat.
So let me explain what I have against Go. Also, just as a disclaimer, I don’t like hating on languages too much. Most of them just want to be tools and have their own shortcomings. But a lot of problems Go experiences seem to be self-imposed restrictions through an ideology that wilfully ignores decades of important language research, which just doesn’t make sense to me.
xetera.dev
Golang is not a good language
Xetera's Blog
#prog #go #java #article
NilAway: Practical Nil Panic Detection for Go
Инструмент для статического анализа кода на Go для обнаружения потенциальных разыменований nil-указателей. В отличие от прочих решений, решающих эту проблему, NilAway быстр, анализирует код между функциями (и даже между пакетами) и поддерживает инкрементальный анализ. При всём этом он не требует никаких аннотаций в коде.
А ранее Uber сделали аналогичный инструмент для Java, NullAway.
NilAway: Practical Nil Panic Detection for Go
Инструмент для статического анализа кода на Go для обнаружения потенциальных разыменований nil-указателей. В отличие от прочих решений, решающих эту проблему, NilAway быстр, анализирует код между функциями (и даже между пакетами) и поддерживает инкрементальный анализ. При всём этом он не требует никаких аннотаций в коде.
А ранее Uber сделали аналогичный инструмент для Java, NullAway.
#prog #go #suckassstory
Пусть есть вот такая простая программа на Go:
Если запустить эту программу при отсутствии сетевого подключения (например, на Go playground), то программа печатает ошибку и... Валится с nil pointer dereference:
Почему так — в Go же в целом методы обычно не паникуют с nil-ресивером? Функция net.Dial из стандартной библиотеки возвращает
Так вот, как пояснено в 50 shades of Go, у присваивания интерфейсам
Да, это значит, что поведение может поменяться, если
(thanks @HowToGoWrong)
Пусть есть вот такая простая программа на Go:
package main
import (
"fmt"
"net"
)
func main() {
func() {
f, err := net.Dial("tcp", "1.1.1.1:443")
defer f.Close()
fmt.Println(err)
}()
}
Если запустить эту программу при отсутствии сетевого подключения (например, на Go playground), то программа печатает ошибку и... Валится с nil pointer dereference:
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x4d0adb]
goroutine 1 [running]:
main.main.func1()
/tmp/sandbox1770654708/prog.go:11 +0x3b
main.main()
/tmp/sandbox1770654708/prog.go:14 +0xf
Почему так — в Go же в целом методы обычно не паникуют с nil-ресивером? Функция net.Dial из стандартной библиотеки возвращает
(Conn, error)
, где Conn
— не конкретный тип, а интерфейс (почему он включает в себя методы Read
и Write
вместо включения интерфейсов io.Reader и io.Writer — отдельный вопрос).Так вот, как пояснено в 50 shades of Go, у присваивания интерфейсам
nil
есть два значения. Если интерфейсу присваивается nil
-значение некоего не-интерфейсного типа, который может быть nil
(скажем, некий указатель), то значимая часть интерфейса также будет nil
, но указатель на таблицу методов будет заполнен от типа присваиваемого значения. Такая переменная будет давать false
при тестирование на равенство с nil
. Если же значению интерфейсного типа присвоить литерал nil
напрямую (или просто не инициализировать явно), то тип нижележащего значения вывести неоткуда, а потому и значимая часть интерфейса, и указатель на таблицу методов будут nil
. Такое значение будет давать true
при тестировании на равенство с nil
.net.Dial
, как и большинство функций в Go, возвращают первым значением nil
в случае ошибки. В коде выше в конце main
после Println
срабатывает код в defer
, который пытается вызывать метод Close
, и так как у nil
-интерфейса указатель на таблицу методов является nil
, рантайм паникует, так как вытащить метод из ниоткуда, очевидно, нельзя.Да, это значит, что поведение может поменяться, если
net.Dial
начнёт возвращать первое значение при ошибке иначе.(thanks @HowToGoWrong)
go.dev
Go Playground - The Go Programming Language
#prog #go #article
Understanding Real-World Concurrency Bugs in Go (PDF)
In this paper, we perform the first systematic study on concurrency bugs in real Go programs. We studied six popular Go software including Docker, Kubernetes, and gRPC. We analyzed 171 concurrency bugs in total, with more than half of them caused by non-traditional, Go-specific problems. Apart from root causes of these bugs, we also studied their fixes, performed experiments to reproduce them, and evaluated them with two publicly-available Go bug detectors.
<...>
Our study found that message passing does not necessarily make multithreaded programs less error-prone than shared memory. In fact, message passing is the main cause of blocking bugs.
<...>
We believe that message passing offers a clean form of inter-thread communication and can be useful in passing data and signals. But they are only useful if used correctly, which requires programmers to not only understand message passing mechanisms well but also other synchronization mechanisms of Go.
Надо отметить, что результаты могут быть искажены тем, что:
а) выборка только из шести проектов (Docker, Kubernetes, etcd, CockroachDB, BoltDB, gRPC-go);
б) рассматриваются только баги, которые были исправлены.
Understanding Real-World Concurrency Bugs in Go (PDF)
In this paper, we perform the first systematic study on concurrency bugs in real Go programs. We studied six popular Go software including Docker, Kubernetes, and gRPC. We analyzed 171 concurrency bugs in total, with more than half of them caused by non-traditional, Go-specific problems. Apart from root causes of these bugs, we also studied their fixes, performed experiments to reproduce them, and evaluated them with two publicly-available Go bug detectors.
<...>
Our study found that message passing does not necessarily make multithreaded programs less error-prone than shared memory. In fact, message passing is the main cause of blocking bugs.
<...>
We believe that message passing offers a clean form of inter-thread communication and can be useful in passing data and signals. But they are only useful if used correctly, which requires programmers to not only understand message passing mechanisms well but also other synchronization mechanisms of Go.
Надо отметить, что результаты могут быть искажены тем, что:
а) выборка только из шести проектов (Docker, Kubernetes, etcd, CockroachDB, BoltDB, gRPC-go);
б) рассматриваются только баги, которые были исправлены.
ACM Conferences
Understanding Real-World Concurrency Bugs in Go | Proceedings of the Twenty-Fourth International Conference on Architectural Support…
Forwarded from Находки в опенсорсе
Статический анализ GitHub Actions
Сразу после релиза новой версии линтера, я задался вопросом обновления своего шаблона для создания новых питоновских библиотек: https://github.com/wemake-services/wemake-python-package
И я понял, что я несколько отстал в вопросе стат анализа GitHub Actions и прочей инфраструктуры.
Расскажу о своих находках.
pre-commit ci
Все знают про пакет pre-commit? Несколько лет назад он получил еще и свой собственный CI, который умеет запускаться без дополнительного конфига. И автоматически пушить вам в ветку любые изменения. Что супер удобно для всяких
Строить CI на базе
- Автоматически исправляются многие проблемы
- Автоматически запускается CI, 0 настроек
- Локально все тоже работает одной командой:
actionlint
Первый раз я увидел
Даже умеет автоматом shellcheck запускать на ваши
zizmor
Исходники. Уже на #rust, он более злой. Делает похожие вещи: находит проблемы безопасности. Находит много проблем.
Вот пример, сколько всего он нашел в mypy.
check-jsonschema
Еще есть вот такой проект, он в основном полезен за счет доп интеграций: можно проверять
Ставится просто как:
Выводы
Как всегда – статический анализ многому меня научил. Я узнал много нового про безопасность GitHub Actions, про вектора атаки, про лучшие практики. А сколько проблем в ваших actions?
Скоро ждите весь новый тулинг в python шаблоне
Сразу после релиза новой версии линтера, я задался вопросом обновления своего шаблона для создания новых питоновских библиотек: https://github.com/wemake-services/wemake-python-package
И я понял, что я несколько отстал в вопросе стат анализа GitHub Actions и прочей инфраструктуры.
Расскажу о своих находках.
pre-commit ci
Все знают про пакет pre-commit? Несколько лет назад он получил еще и свой собственный CI, который умеет запускаться без дополнительного конфига. И автоматически пушить вам в ветку любые изменения. Что супер удобно для всяких
ruff
/ black
/ isort
и прочего. У нас такое стоит в большом количестве проектов. Вот пример из typeshed. Вот что поменялось автоматически. Строить CI на базе
pre-commit
очень удобно, потому что тебе просто нужно скопировать пару строк в конфиг. А плюсов много:- Автоматически исправляются многие проблемы
- Автоматически запускается CI, 0 настроек
- Локально все тоже работает одной командой:
pre-commit run TASK_ID -a
actionlint
Первый раз я увидел
actionlint
внутри CPython и затащил его в mypy. Actionlint на #go, он предлагает набор проверок для ваших GitHub Actions от безопасности до валидации спеки вашего yml. Довольно полезно, позволяет найти много мест для улучшений.
test.yaml:3:5: unexpected key "branch" for "push" section. expected one of "branches", ..., "workflows" [syntax-check]
|
3 | branch: main
| ^~~~~~~
test.yaml:10:28: label "linux-latest" is unknown. available labels are "macos-latest", ..., "windows". if it is a custom label for self-hosted runner, set list of labels in actionlint.yaml config file [runner-label]
|
10 | os: [macos-latest, linux-latest]
| ^~~~~~~~~~~~~
test.yaml:13:41: "github.event.head_commit.message" is potentially untrusted. avoid using it directly in inline scripts. instead, pass it through an environment variable. see https://docs.github.com/en/actions/security-for-github-actions/security-guides/security-hardening-for-github-actions for more details [expression]
|
13 | - run: echo "Checking commit '${{ github.event.head_commit.message }}'"
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Даже умеет автоматом shellcheck запускать на ваши
run:
скрипты!zizmor
Исходники. Уже на #rust, он более злой. Делает похожие вещи: находит проблемы безопасности. Находит много проблем.
Вот пример, сколько всего он нашел в mypy.
warning[artipacked]: credential persistence through GitHub Actions artifacts
--> mypy/.github/workflows/mypy_primer.yml:37:9
|
37 | - uses: actions/checkout@v4
| _________-
38 | | with:
39 | | path: mypy_to_test
40 | | fetch-depth: 0
| |________________________- does not set persist-credentials: false
|
= note: audit confidence → Low
error[dangerous-triggers]: use of fundamentally insecure workflow trigger
--> mypy/.github/workflows/mypy_primer_comment.yml:3:1
|
3 | / on:
4 | | workflow_run:
... |
7 | | types:
8 | | - completed
| |_________________^ workflow_run is almost always used insecurely
|
= note: audit confidence → Medium
check-jsonschema
Еще есть вот такой проект, он в основном полезен за счет доп интеграций: можно проверять
dependabot.yml
, renovate.yml
, readthedocs.yml
и многое другое.Ставится просто как:
- repo: https://github.com/python-jsonschema/check-jsonschema
rev: 0.30.0
hooks:
- id: check-dependabot
- id: check-github-workflows
Выводы
Как всегда – статический анализ многому меня научил. Я узнал много нового про безопасность GitHub Actions, про вектора атаки, про лучшие практики. А сколько проблем в ваших actions?
Скоро ждите весь новый тулинг в python шаблоне
v2025
😎GitHub
GitHub - wemake-services/wemake-python-package: Bleeding edge cookiecutter template to create new python packages
Bleeding edge cookiecutter template to create new python packages - wemake-services/wemake-python-package
#prog #typescript
В Microsoft решили из-за проблем с производительностью переписать компилятор Typescript с Typescript на... #Go. Выбор языка аргументируют сочетанием контроля над раскладкой структур в памяти вкупе со сборщиком мусора и лёгкостью портирования уже имеющегося кода. На мой взгляд, очень странный выбор.
Производительность, впрочем, действительно улучшилась — прототип уже в состоянии компилировать реальные проекты на порядок быстрее.
В Microsoft решили из-за проблем с производительностью переписать компилятор Typescript с Typescript на... #Go. Выбор языка аргументируют сочетанием контроля над раскладкой структур в памяти вкупе со сборщиком мусора и лёгкостью портирования уже имеющегося кода. На мой взгляд, очень странный выбор.
Производительность, впрочем, действительно улучшилась — прототип уже в состоянии компилировать реальные проекты на порядок быстрее.
Microsoft News
A 10x Faster TypeScript
Embarking on a native port of the existing TypeScript compiler and toolset to achieve a 10x performance speed-up.