LINUX.ORG.RU
ФорумTalks

А как вообще Go взлетел?

 


1

3

Решил вот посмотреть на язык, читаю, дошел до слайсов.

                                                                                                                                                                                                         
package main

import (
	"fmt"
)

func main() {
	a := []int{1, 2, 3, 4, 5}
	b := []int{1, 2, 3, 4, 5}
	c := a[1:3]
	d := b[1:5]
	c = append(c, 10)
	d = append(d, 10)
	c[0] = 0
	d[0] = 0
	fmt.Println(a)
	fmt.Println(b)
	fmt.Println(c)
	fmt.Println(d)
}
Вывод:
[1 0 3 10 5]
[1 2 3 4 5]
[0 3 10]
[0 3 4 5 10]

То есть в зависимости от одного индекса зависит, будет ли меняться низлежащий массив или нет. Да, я знаю про синтаксис [1:3:3], но это избыточность, и по умолчанию так же все равно не пишут. И если мне это в функцию дают, мне что, каждый раз сравнивать size и capacity, чтобы дел не напороть? А учитывая, что я не могу в сигнатуре функции указать константность, это еще сильнее усугубляет.
Ну а про классические претензии вроде отсутствия дженериков и перегрузки, но при этом существования generic-like встроенных типов с ad-hoc синтаксисом, жуткой обработки ошибок и прочего, я уж молчу, это давно уже обсосали везде. Вот и вопрос, как оно взлетело?

★★

Последнее исправление: keyran (всего исправлений: 1)

Ответ на: комментарий от Hertz

Метапрограммирование то в гошечке есть?

Там много чего нет. Генериков нет, из-за чего местами «блочное копирование заменяет алгоритмическое программирование». Исключений нет, перегрузки нет…

baka-kun ★★★★★
()
Ответ на: комментарий от baka-kun

Справедливости ради, в Golang тоже сборщик мусора. Которые по сути не настраивается

Настраивается. Просто ручка всего одна.

и не отдаёт сразу освобожденную память системе.

Сразу не отдает, но отдает через некоторое время. ЕМНИП, 5 минут.

feofan ★★★★★
()
Ответ на: комментарий от baka-kun

Исключений нет, перегрузки нет…

И они преподносят это как фичу, а не баг. Про исключения они в какой-то мере правы. Обязательный try-catch в java порой сильно трахает мозг.

Deleted
()
Ответ на: комментарий от feofan

Причем тут массивы? Слайсы, они же срезы - это части исходного массива. И операции с ними не должны влиять ни на что, что находилось за их пределами в момент среза. Во всех нормальных языках операция слайса либо возвращает фиксированное окно, либо вытаскивает вообще новый массив. А тут слайсом вдруг назвали динамический массив, который может разделять память с кучей других массивов, и мало того, корежить память, которая ему не принадлежит, и с которой в момент его создания вообще с ним не делились.

keyran ★★
() автор топика
Ответ на: комментарий от Deleted

Метапрограммирование есть почти везде. Оно есть и в Haskell, и в Python, и в куче других языков. Как раз в C++ на текущий момент оно достаточно неприятное, хотя сильные подвижки в этом направлении как раз сейчас и производятся.

keyran ★★
() автор топика
Ответ на: комментарий от keyran

Инициализируй слайс копией части оригинального массива, и получишь поведение как во «всех нормальных».

baka-kun ★★★★★
()
Ответ на: комментарий от Deleted

Про исключения они, возможно, и правы, а вот в том, что у них нет вариативных типов, и вместо варианта они возвращают пару (причем встроенных кортежей, кстати, тоже нет :), причем один из элементов этой пары практически всегда nil, вот это жуть.

keyran ★★
() автор топика
Ответ на: комментарий от baka-kun

Уже был такой коммент. Эмулировать поведение через дополнительные действия можно всегда, тут вопросов нет. Но поведение по умолчанию очень легко может привести к выстрелу в ногу, то есть повреждению другого слайса. И что еще хуже, в зависимости от того, каков был верхний индекс этого слайса, это поведение может и не привести к повреждению при абсолютно тех же операциях.

keyran ★★
() автор топика
Ответ на: комментарий от Deleted

NP так-то. Это похуже дробилки будет

Хуже или лучше - неважно. Числодробилка - это задача вычислительной математики.

tailgunner ★★★★★
()
Ответ на: комментарий от keyran

Во всех нормальных языках

Список нормальных языков в студию

корежить память, которая ему не принадлежит, и с которой в момент его создания вообще с ним не делились.

Почитай уже про backed array. То, что поведение соответствует документации, а не фантазиям рандомного человека я криминалом не считаю.

feofan ★★★★★
()
Ответ на: комментарий от feofan

То, что поведение соответствует документации, а не фантазиям рандомного человека я криминалом не считаю.

Задокументировать можно любую дурь, от этого она не перестанет быть дурью.

tailgunner ★★★★★
()
Ответ на: комментарий от tailgunner

Дык проблема перебора это что, не вычислительная математика? «Хуже», всмысле по времени расчеты очень трудоемкие.

Deleted
()
Ответ на: комментарий от feofan

Список нормальных языков в студию

Из тех, о которых я знаю (не все могу назвать прямо нормальными), и в которых есть встроенная или стандартная операция slice: python (работает как фиксированное окно, если rvalue, при присваивании возвращает копию), rust (фиксированное окно), js (возвращает копию части массива), ruby (возвращает копию части массива)... Ни один из них не позволяет затереть то, что было вне слайса.

Почитай уже про backed array. То, что поведение соответствует документации, а не фантазиям рандомного человека я криминалом не считаю.

От того, что design flaw задокументировали, он не перестает им быть.

keyran ★★
() автор топика
Ответ на: комментарий от Deleted

Ну да, крестовики — знатные обфускаторы. Хлебом не корми.

Hertz ★★★★★
()
Ответ на: комментарий от keyran

Ну тут нюанс в том, что COW в языке нет, иммутабельности нет. Это можно отнести к недостаткам языка, но к данной теме непосредственного отношения не имеет. А делать неявное копирование нижележащего массива при создании слайса я не считаю правильным. Текущее поведение полностью консистентно тому, как в go работают все ссылочные типы.

feofan ★★★★★
()
Ответ на: комментарий от feofan

Аргументировать то, что данный конкретный пример - «дурь» можешь?

Я говорил о том, что «соответствие документации» - это не аргумент.

Без эмоций, фактами.

Моя религия говорит, что shared mutable state - это плохо, потому что является источником ошибок и неочевидного поведения. Если state еще и мутирует неочевидными способами (как в примере) - дело передается священной инквизиции. Какие эмоции, о чем ты.

tailgunner ★★★★★
()
Последнее исправление: tailgunner (всего исправлений: 1)
Ответ на: комментарий от feofan

Так я же и не говорю про требование к иммутабельности. Если бы операция слайсинга по умолчанию работала как сейчас работает [a:b:b], то есть первая же операция append делала бы неявное копирование, было бы претензий меньше. Хотя, это решает только часть проблемы, связанной с неявностю переаллокации, но

c := a[1:5]
c[0] = 3 // меняет a
c = append(c,10)
c[0] = 4 // не меняет a
Но здесь уже можно с чистой совестью сказать, что видно, что _c_ до append — это не то же самое, что _c_ после append.

keyran ★★
() автор топика
Ответ на: комментарий от tailgunner

shared mutable state - это плохо, потому что является источником ошибок и неочевидного поведения

Полностью согласен. Есть конечно инструменты, чтобы такие вещи находить. Например, race detector. Но он работает только в рантайме, требует указания флага при компиляции, а также, по очевидным причинам замедляет выполнение, поэтому не самый лучший инструмент.

Если state еще и мутирует неочевидными способами (как в примере)

Я вот в этом моменте не согласен. Мутирует вполне очевидными способами. А вот отсылку к «нормальным языкам» я считаю неубедительным аргументом.

feofan ★★★★★
()
Ответ на: комментарий от feofan

Я вот в этом моменте не согласен. Мутирует вполне очевидными способами.

Очевидными? Нет. Соответствующими документации — да. Как можно назвать очевидным случай, когда при одинаковых операциях совершенно по разному меняется shared state?

А вот отсылку к «нормальным языкам» я считаю неубедительным аргументом.

Это не аргумент, это пример. Чаще всего в язык люди приходят из других языков, и если почти во всех языках за границы slice выйти нельзя, то человек будет ожидать, что нельзя и здесь.

keyran ★★
() автор топика
Ответ на: комментарий от feofan

Я вот в этом моменте не согласен. Мутирует вполне очевидными способами.

Мне кажется, ты просто привык.

А вот отсылку к «нормальным языкам» я считаю неубедительным аргументом.

Почему? Go ведь не первый ЯП на этой планете. Люди, которые программируют на Go, раньше программировали на чем-то другом, и противоречить накопленному ими опыту без веских причин - как минимум глупо.

tailgunner ★★★★★
()
Ответ на: комментарий от tailgunner

Мне кажется, ты просто привык.

Возможно.

Люди, которые программируют на Go, раньше программировали на чем-то другом, и противоречить накопленному ими опыту без веских причин - как минимум глупо.

В целом мысль верная. Но, в го есть своя внутренняя непротиворечивая логика, понять и запомнить которую несложно, т.к. язык небольшой, стандарт короткий. Ну и у меня, например, когда я это изучал, в голове всплыли аналогии с общелисповыми операциями над списками. Поведение аналогичное чуть менее, чем полностью с учетом контекста.

feofan ★★★★★
()
Ответ на: комментарий от keyran

Как можно назвать очевидным случай, когда при одинаковых операциях совершенно по разному меняется shared state?

Условия разные. В одном случае append в рамках capacity, во втором - append с превышением capacity. Мне кажется, запомнить как работает append не очень сложно.

feofan ★★★★★
()
Ответ на: комментарий от Deleted

похоже, в твоей жизни остро нехватало явы :)

Ну, как не хватало... 10 лет назад я довольно жирным опенсорс-проектом рулил на десяток активных разработчиков :D И первые программы писал в 1997 году.

Но в последние 10 лет, да, Java в руки не брал :D

но клепать новые яп для такого... неубедительно как-то

Так я его не клепал. Я просто готовым пользуюсь :)

KRoN73 ★★★★★
()
Ответ на: комментарий от feofan

Ну, мы же теперь про очевидность говорим. Очевидность - это тогда, когда все происходит явно. Например, если мне передали срез в функцию, и я хочу взять уже его срез из двух элементов (допустим, я знаю, что их там не меньше двух, поскольку это проверяется выше), то мне уже не очевидно, какая у нового среза будет capacity, мне это надо явно проверять. Соответственно, мне не очевидны сайд-эффекты всех последующих операций. Очевидно было бы, если бы capacity среза была по умолчанию равна его размеру, и синтаксис [a:b:c] был бы нужен в случае, если надо задать отличную от него capacity.

keyran ★★
() автор топика
Ответ на: комментарий от keyran

Очевидно, что если ты хочешь мутировать slice и не хочешь аффектить backed array, ты должен явно этот slice скопировать. Остальное выглядит как домыслы.

feofan ★★★★★
()
Последнее исправление: feofan (всего исправлений: 1)
Ответ на: комментарий от feofan

Подход других языков программирования: переходить дорогу аккуратно, но если очень надо – быстро перебежать в неположенном месте.

Подход Go: всегда перебегать дорогу где попало, потому что быстрее, но иногда всё же переходить безопасным способом.

Подход други языков: даёшь человеку документ для ознакомления, ожидаешь, что тебе вернут его целым.

Подход Go: отдавая документ человеку, сразу готов, что он на нём будет рисовать, может порвёт его немного; если документ жалко – даёшь человеку копию документа.

uuwaan ★★
()
Ответ на: комментарий от uuwaan

Люблю, когда человек вместо технических аргументов использует аналогии - сразу становится понятным уровень этого человека и необходимость учитывать его мнение.

feofan ★★★★★
()
Ответ на: комментарий от feofan

Технические были выше.

Текущее умолчальное поведение слайса неконсистентно с позицией авторов языка, что Go «как Си, но немного безопаснее». Из двух альтернатив поведения по умолчанию они выбрали менее безопасную в данном случае.

uuwaan ★★
()
Ответ на: комментарий от feofan

Ок. Это аргумент. И если я хочу, чтобы сторонняя функция мне не испортила слайс, я должен его тоже сначала скопировать, прежде, чем передавать, так?

keyran ★★
() автор топика
Последнее исправление: keyran (всего исправлений: 2)
Ответ на: комментарий от uuwaan

Не нашел в посте по ссылке технических аргументов, одни эмоции.

Из двух альтернатив поведения по умолчанию они выбрали менее безопасную в данном случае.

В го много мест, где безопасность приносится в жертву ради чего-то, что сочли более приоритетным в данном случае. Например, скорость компиляции.

А необходимость аккуратной работы со ссылочными типами упоминается примерно везде. Аллокации - дорогое удовольствие. Так что логика в выборе решений у авторов языка вполне прослеживается. То, что она кому-то не нравится, или для кого-то неочевидна не значит, что её нет.

feofan ★★★★★
()
Ответ на: комментарий от keyran

На уровне соглашений считается хорошим тоном копировать уже там, где ты мутируешь. Но если ты не уверен в вызывающей стороне, ничего другого не остается.

feofan ★★★★★
()
Ответ на: комментарий от feofan

Ну еще существуют функции, которые мутируют по определению, семантика у них такая. Например, глупо ожидать, что функция Sort не будет менять слайс. И если ты такие функции используешь, но хочешь оригинальный массив оставить нетронутым, очевидно, что ты должен вызвать копирование явно.

feofan ★★★★★
()
Ответ на: комментарий от feofan

Не, это понятно. Было бы, конечно, приятно видеть это в сигнатуре функции, но понятно, что ради скорости компиляции указанием, и тем более, обеспечением константности пожертвовали. Я, правда, этим тоже недоволен, но тут это, действительно, лично мое мнение.

keyran ★★
() автор топика
Ответ на: комментарий от Joe_Bishop

Хз. Заслуги java в этом точно нет.

Deleted
()

Вот и вопрос, как оно взлетело?

Пустовала ниша компилируемого и простого ЯП. Для тех, кто не осилил джаву. Вот это поделие и заняло нишу. А с учетом огромного рынка индуского кода, оно продолжит свой стабильный полёт, если гугл его по итогу не закроет. Например, когда выплатит штраф Oracle и сраться будет не о чем. И/или когда джава станет компилируемой и с коурутинами.

foror ★★★★★
()
Последнее исправление: foror (всего исправлений: 1)
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.