Comments 52
Судя по тому что рассказывают докладчики у Go есть только одно преимущество, можно легко и быстро создавать кучу легковесных потоков. В остальном не язык, а один сплошной архаизм поощряющий костылестроение в попытках обойти его конструктивные недостатки.
В наше время есть серверы, не использующие ту или иную реализацию параллельного выполнения запросов от клиентов?
В наше время есть cli-утилиты (например, сконвертить один файл в другой)
В наше время есть однопоточный bolt.
Параллельность — это ещё не всё.
Go — это не «язык с прикольной параллельностью, но вот жаль нет дженериков, ООП, эксепшенов, тьфу убогая архитектура».
На Go действительно можно быстро писать код, и не только многопоточный/конкуррентный.
Прошу заметить, что это не означает, что нельзя программировать на D/Rust/Scala/etc.
Я уточнял исключительно про серверы.
Я еще раз сделаю акцент на том, что Go подходит для создание кучи легковесных потоков, но совершенно не подходит для обработки данных (хотя если упороться можно хоть числодробилку на PHP написать).
package main
import "fmt"
func int64Sum(list []int64) (uint64) {
var result int64 = 0
for x := 0; x < len(list); x++ {
result += list[x]
}
return uint64(result)
}
func int32Sum(list []int32) (uint64) {
var result int32 = 0
for x := 0; x < len(list); x++ {
result += list[x]
}
return uint64(result)
}
func int16Sum(list []int16) (uint64) {
var result int16 = 0
for x := 0; x < len(list); x++ {
result += list[x]
}
return uint64(result)
}
func int8Sum(list []int8) (uint64) {
var result int8 = 0
for x := 0; x < len(list); x++ {
result += list[x]
}
return uint64(result)
}
func main() {
list8 := []int8 {1, 2, 3, 4, 5}
list16 := []int16{1, 2, 3, 4, 5}
list32 := []int32{1, 2, 3, 4, 5}
list64 := []int64{1, 2, 3, 4, 5}
fmt.Println(int8Sum(list8))
fmt.Println(int16Sum(list16))
fmt.Println(int32Sum(list32))
fmt.Println(int64Sum(list64))
}
Тоже самое на D. В которому впрочем поддержка этих же легковесных потоков тоже есть.
import std.stdio;
import std.algorithm;
void main(string[] args)
{
[1, 2, 3, 4, 5].reduce!((a, b) => a + b).writeln;
}
но совершенно не подходит для обработки данных
У каждого свои данные. Я вот пишу что-то типа Socorro, но с поддержкой emscripten. Данными являются файлы символов, минидампы, то что сваливается в GlobalEventHandlers.onerror.
[0, 1, 2, 3, 4].reduce(function(previousValue, currentValue, index, array) {
return previousValue + currentValue;
});
и сказать, что JS аж на пять строк короче, чем D…А как насчёт сопровождения такого кода? Как насчёт отлова ошибок с данными на этапе компиляции? Тесты производительности гоняли?
В Вашем примере на D только один массив непонятного размера и бизнес-логика (суммирование) не вынесено в отдельную функцию. Если же создать 4 массива с элементами разных размеров и не инлайнить функцию суммирования (а написать template, который будет понимать разные типы), то кода будет чуть больше… Но в целом Ваши негодования понятны — отсутствие в стандартной библиотеки функции reduce (есть сторонние реализации) и отсутствие generic-ов — на эту тему уже много написано, даже авторами языка.
Мне кажется, что желание дженериков везде и всегда, сродни преждевременной оптимизации или неоправданному расширению задачи: надо было сделать для одного типа, но программист пробует написать обобщенный код.
Дженерики нужны, конечно, кодогенерация не помогает всегда, да и код усложняет в разы, как и отладку сгенерированного кода. И в самой стандартной библиотеке она не используется, то есть это решение и разработчикам golang не сильно нравится.
Но да, дженерики не настолько важны в действительной жизни. Рабочий код пишется и без них.
+/1 2 3 4 5
package main
import "sum"
func main() {
println(sum.Int8([]int8 {1, 2, 3, 4, 5}))
}
чем пытаться понять из какого пакета прилетела функциональность writeln или reduce (соответственно, чем больше проект и больше пактов, тем сложнее, опять же для меня, все это поддерживать), так что только на основании этого я бы не стал утверждать, что он (Go) категорично не подходит для обработки данных
ЗЫ: и у D и у Go есть свои плюсы, но Go, в моем случае, предпочтительнее в силу своей очевидности
Не работал с Go, но слышал, что там не реализованы исключения. Есть ли какой-то устоявшийся альтернативный подход к выбрасыванию и обработке исключений?
Почему же. Дело в том, что вместо привычного механизма исключений в Go предлагается несколько вариантов, но все они с первого взгляда какие-то неудобные. Есть даже библиотеки, которые пытаются воспроизвести что-то близкое к привычным исключениям. Может это и нормально, но для человека, не работающего с Go, это выглядит странно. Поэтому вполне нормальный вопрос.
Мне вот не понравился rust, не смог привыкнуть к его «свистульками и погремушкам», причем на уровне ощущений и эмоций, т.е. я не смогу объяснить — чем именно не понравился. Нет, так нет, я и не читаю статьи про rust.
А что раст? Там тоже "нет исключений". Просто перестроится сложно и не всегда понятное даёт ли это хоть какие-то преимущества. Люди привыкли жить с исключениями и находят в этом определённое удобство. Тут надо показать преимущества другого подхода, а не просто предлагать забыть о предыдущем опыте.
А «не фигово было бы изучить go, но в нем обработка ошибок какая-то неудобная...» я не понимаю. После подобного хочется спросить «Ииии?!» Дальше-то что? Если человек хочет узнать, как эта неудобная обработка ошибок работает и как ей пользоваться, ну, так «google в помощь» — информации навалом.
А про раст — мне неважно, есть там исключения или нет; если у меня хватит терпения и времени я приму его модель и неважно — насколько она отличается от go, python, php, lua (других языков я не знаю).
Для человека, работавшего со, скажем так, Фортран и Си-подобными языками, некоторые варианты, предлагаемые Go, в частности возвращение из функций двух значений, одно из которых является и признаком, и сообщением об ошибке, являются куда более удобными, чем привычное либо возвращение ошибки магическим числом, либо падение процесса. Привычные по С++ подобным языкам исключения с раскруткой стека вызовов чащего всего используются не по назначению, не для обработки исключительных ситуаций, а для ветвления в зависимости от каких-то определенных условий.
Но для пробы посмотрел вторую лекцию и был удивлен: в лекции рассматриваются вопросы, которых или не существует или они по-другому работают в go. Рассмотрена передача параметров по ссылке и значению, но в go есть только передача по значению; предупреждается о переполнении стэка — ну это возможно, если всю память переполнить, впринципе…
Рассмотрена передача параметров по ссылке и значению, но в go есть только передача по значениюВ Golang есть передача по указателю ( http://golang-book.ru/chapter-08-pointers.html ) ну и для особых случаев пакет unsafe если уж действительно надо поработать на низком уровне.
Можно сделать указатель, но в функцию его передашь все равно по значению. С unsafe то же самое. Ну будет uintptr — это не ссылка, а вполне себе значение.
Спосибо
В первой лекции в конце ошибка, при передаче слайса и сложных типов, они НЕ передаются по ссылке, а передается копия структуры с указателем (копия дескриптора переменной). Если внутри фугкции произойдет изменение этого аргумента такое, что потребует реаллокации массива в памяти, то внутри функции создастся копия слайса с массивом, и снаружи функции дальнейшие изменения уже не будут видны. Поэтому и рекомендуют передавать указатели на сложные типы, а не сами переменные типа.
Лекции Техносферы: Программирование на Go