Pull to refresh

Comments 96

В принципе, аргументация понятная, но ответ на вопрос, хорош ли язык для обучения программированию можно дать только на основе реального опыта использования его в таком качестве. Потому что не исключено, что избавившись от одних подводных камней, создатели языка набросали других.
Я вот Go не знаю, но например на C++ можно точно также писать на небольшом его подмножестве, даже включив опции комилятора «считать предупреждения за ошибки», все будет тоже также валится. А можно и на C++/CLI перейти для надежности.

Так чем таки Go хорошь?
Пока я читал ваш комментарий, у меня случился Error: Segmentation fault
А если серьезно, то я сам начинал обучение с C и C++.
Какой довод вам не ясен из перечисленных?
Все доводы слишком туманные и неочевидные, хорошо если бы конкретные примеры это показывали. Насчет простоты:

C++ сегодня прост, как и бейсик в 80ые

#include «basic.hpp»

int main()
{
_10: LET X = 1;
_20: LET SUM = 0;
_30: LET DEPTH = 1;
_40: INPUT «Enter a positive number: », X;
_50: IF X > 0 THEN GOTO _130;
_60: PRINT «By positive, I mean greater than zero. You entered », X, " which isn't";
_70: GOTO _40;
_80: SUM = SUM + X;
_90: X = X — 1;
_100: IF X > 0 THEN GOSUB _80;
_110: DEPTH = DEPTH * 2;
_120: RETURN;
_130: GOSUB _80;
_140: PRINT «SUM=», SUM, " DEPTH=", DEPTH;
}

https://github.com/rollbear/basicpp
Как бы я ни хотел найти лучшую замену Питону для обучения, но Go для этого не создавался. Насколько я помню, львиную долю времени мы, будучи школьниками и студентами, писали алгоритмы и структуры данных. Без обобщений такие вещи делать некрасиво, а пользоваться втсроенными в язык — значит ничему не научиться.

И раз уж мы затронули эту злободневную тему, не расскажете ли преимущества «бутсрапинга или кодогенерации» перед нормальными обобщениями?
Чтобы было что обобщать, надо для начала научиться делать частности. Генерики формируют дополнительный слой абстракции, который на начальном этапе не нужен…
Я по большей частью согласен, НО «дополнительный слой абстракции» — это скорее про «бутсрапинг или кодогенерация», чем про нормальные родные обобщения. К тому же, никто не заставляет их сразу использовать.
Кодогенерация это инструмент, а не конструкция языка. Как-то специально его изучать в рамках дисциплины программирования смысла нет.
Скажите пожалуйста, когда последний раз, в реальном проекте, вы действительно были вынуждены писать свою структуру данных, которая действительно нуждается в обобщениях? Будьте добры, наведите юскейс.
Как минимум год назад, но суть не в этом. Речь идёт про обучение, где нужно понять, как такие вещи в принципе делаются, прежде чем бросаться использовать библиотечные функции.
Я не вижу потребности в обобщенном программировании при обучении.
Давайте тогда уже и механизм исключений не изучать, раз его в Go не завезли. И наследование, и алгебраические типы, и функциональное программирование. Вы понимаете, какова вообще суть обучения?
Мы говорим про обучение программированию в принципе или на конкретном ЯП? Что исключения, что алгебраические типы, что функиональщина — это специфические для того или иного ЯП фишки.
Go достаточно многословный и строгий язык программирования с очень предсказуемой и стремительной кривой обучения, что делает его крайне удачной технологией для обучения программированию новоприбывших!

Я так понял контекст, что речь идёт о программировании в целом. Исключения есть практически во всех широко используемых языках, проще перечислить, где их нет (Go, Rust, что ещё?). Алгебраические типы также есть во многих языках: Scala, Erlang, Haskell, Rust, etc. Сказать, что это специфические ЯП фишки — явное лукавство.
Я не могу понять суть ваших претензий, но да, в контексте речь о программировании в целом.
Как вы выражаетесь, «функциональщина» — это не специфические для ЯП «фишки», а целый подход к программированию, который планомерно ползет в языке, где раньше никакого ФП не было. И это и к лучшему.
Дело в том, что ФИШКИ из ФП есть далеко не везде и я не считаю необходимым в обязательном порядке их изучать.
Так не изучайте фишки, изучайте подход. Собственно, это ведь ровно для того и делается — чтобы знать, что еще бывает за пределами известных тебе языков, чтобы выбирать язык и инструмент под задачу.
Я вообще ничего против функциональных ЯП не имею, интересная область. Я просто считаю, что тут за уши функциональщину притянули. Изначальная претензия была формата: «а как это так ты собираешься учить программированию и не расскажешь про алгебраические типы, да?!», вообщем-то и притянутая за уши.
А это как раз очень правильная по духу претензия. Обучая программированию надо рано или поздно показывать все более-менее распространенные инструменты, чтобы в будущем они не вызывали непонимания.
И какое это имеет отношение конкретно к языку Go, как языку для обучения программированию?
Вероятно, такое, что он не так хорошо для этого подходит, как вы пытаетесь показать?
Я не говорил, что Go это язык, который научит ВСЕМУ программированию. Функциональное программирование — это вовсе не необходимое, а скорее вероятное подмножество в соотв. навыке.
Знаете, а так можно о чем угодно сказать — что это вовсе не необходимое, а вероятное подмножество. Кроме умения думать, которому ни один язык не научит.

Разговор, заметим, начался не с ФП, а с дженериков, обучение которым вы тоже не считаете нужным. Чем обосновано ваше «это не нужно» и «это нужно»?
Дженерики не то чтобы не нужны, скорее просто не необходимы. Программировать можно и без них, ровно как и без map/reduce. Конкретно дженерики вводят слишком много непрозрачности, чтобы навязывать их прямо-таки начинающим программистам.
Программировать можно много без чего. Как вы определяете, что нужно, а что нет в обучении?

(И нет, не надо ничего навязывать, надо показывать возможности.)
Тут мы уже упираемся в мнения. Это мои личное ИМХО, у кого-то оно может быть другим.
Вообще-то имхо неплохо бы обосновывать, раз уж вы с ним выходите в публичное пространство.
Понимаете, в чём ирония… Ладно бы там вообще не было обобщений, как в С. А то ж есть, вот они (map, array), но даны богом свыше и недостижимы простым смертным.
Словарь и массив это не обобщения, а стандартные структуры данных.
стандартные обобщённые структуры данных
Ничего «стандартного» в словарях, а особенно в словарях, где типы и ключа, и значения, задаются — нет. Точнее, есть — там, где есть дженерики.
UFO just landed and posted this here
На самом деле то, о чем вы сейчас говорите — это достаточно редкий случай, в котором можно даже кодогенерацию применить. Но в общем случае, список это slice типа interface{}. Оный удовлетворяет абсолютно любые переменные.
Постойте, а разве в Go нету встроенного обобщённого списка?
Ок, встроенными оказались только массивы (array) и отображения (map), насколько я вижу. Аскетичненько так.
На самом деле массивами пользуются очень редко, потому что в них мало силы. Другое дело, слайсы! Но да, встроенных контейнеров больше нету.
Встроеные обобщённые типы — массивы/слайсы, мапы и каналы. Они действительно «даны свыше» и программист сам создать аналогичные типы не может, так устроен язык.
UFO just landed and posted this here
Грубо говоря, гошная статическая система типов в такой задаче сдаётся без боя.
Да, статический type switch:

// element is interface{}

switch casted := element.(type) {
case int: {}
case string: {}
default: {}
}
Постойте, постойте-ка, какой ещё статический? Компилятор, по вашему, знает о типе каждого элемента списка на этапе сборки? Ересь.
Глупость, глупость, глупость. Разумеется, динамический.
ну это совсем не комильфо… всё вроде строго, а тут БАЦ! и разные типы в контейнер помещаются…
если в контексте обучения программированию, то это как-то сбить с толку может и выстроить в голове не правильные логические последовательности и паттерны мышления (контейнер -> нужно проверять тип элемента), которые в других языках будут не всегда работать (проверка типа такая нужно только ЯП с дин. типизацией, о которой Вы в контексте обучения отзываетесь не лестно). но это конечно имхо
сколько ещё неоднородностей подобных язык таит в себе сей?
Вы просто не писали на Go. Приведенный выше пример — это «как можно», а не «как обычно». Обычно никто не использует такие слайсы (а следовательно и проверку типа), а обходятся строго типизированными.
Скажите, а вам нравится буквально копипастить по несколько функций для того, чтобы воспользоваться, например, очередью с приоритетами?
Для изучения алгоритмов и структур данных генерики не нужны (а скорее даже вредны, создают лишний оверхед и ухудшают эффективность структур данных).
Это зависит от их реализации.
Но ты согласен, что для изучения алгоритмов и структур данных они (генерики) не необходимы?
Это интересный вопрос.

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

Так что я бы, наверное, сначала давал без дженериков, а потом бы их добавил.
А организовать пробное обучение Go для тех, кто уже хоть как-то знает хоть какой-то ЯП, скажем в Питере, было бы занятно и познавательно.
"… Реализация требовалась на паскале, а я паскаль знаю очень плохо..."

Уж лучше бы вы не позорили гоферов. После такой заявки как-то рассуждать о Go, как языке обучения, мягко говоря, не комильфо…

Паскаль самое что ни на есть прямое подмножество языка Go, только нет интерфейсов и фигурные скобки заменяются на begin/end. Ну еще пара несущественных нюансов…
Вы сейчас говорите абсолютную ересь! Go действительно взял что-то от паскаля (не так уж и много, к слову), но это не делает последний его подмножеством.
Как вы можете утверждать много/немного, если сами говорите, что плохо знаете Паскаль?.. ))

Единственное, что есть принципиального у Go, чего нет в Паскале — это интерфейсы, замыкания и, в большинстве реализаций Паскаля, функций как базового типа. Всё остальное то же самое, кроме того, что в Паскале:

— Присваивание :=
— Точка с запятой в конце инструкции ставится всегда
— Переменные объявляются всегда
— Есть цикл while

Остальные различия чисто косметические…
Из вашего комментария понял, что паскаль это как Go, только без первого, второго… пятого и десятого, зато присваивание := и точка с запятой есть.

Ну, уже неё плохо… Если бы вы были ещё знакомы с JavaScript, то вы бы ещё поняли про замыкания и тип функция. А интерфейсы это из java…
Go и Pascal это два совершенно разных языка. Pascal действительно оказал влияние на Go, но это влияние не составило и десятой части того, что вложили в спецификацию Go.
Ну, Go это всё равно такой Паскаль с каналами, горутинами и сборщиком мусора :) Мне такого языка не хватало во времена, когда я писал на Паскале — и я ушёл в Java. А сейчас Go — это такой Паскаль, с фичами от JVM-языков.
В Go := не является присваиванием как раз, в отличае от Паскаля. В Go := является объявлением переменной c одновременной её инициализацией, а не присваиванием.

А вот присваивание в Go это =
Читайте внимательно комментарии, на которые отвечаете. Где я написал что в Go := это обычное присваивание?
— Присваивание :=

В Go := это вообще не присваивание. Это инициализация + объявление переменной.
>>Всё остальное то же самое, кроме того, что в Паскале:

>>— Присваивание :=

Отсутствие классов есть недостаток. Все-таки, в реальном мире программирования, классы используются очень часто, и ООП надо учить «с пеленок» (программистских). Я бы сказал, что это одна из основ программирования в принципе, которая неразрывно связана с моделированием объектов (в т.ч. реального мира) и их использованием.
На самом деле, класс — это очень абстрактное понятие. Go это полноценный ООП язык, который реализует инкапсуляцию, наследование, полиморфизм и все вот эти ООПшные примочки.
Я Вам поверю, т.к. не очень хорошо знаком с Go. Есть ссылочка почитать об этом кратенько? Прямо вот чтобы за пару минут понять и просветлиться.
После того, как я поработал с Go, стало очевидно, что то ООП, которое нам продают другие языки — оно не совсем правильное :)
Многие ассоциируют ООП с наследованием, а Go ассоциирует его с интерфейсами. И сейчас я соглашусь с авторами Go, что это гораздо правильнее. Правильнее не с точки зрения определения ООП, а с точки зрения построения архитектуры приложения и его будущего развития. Наследование чаще приносит больше вреда, нежели пользы. Я вообще не видел ни одного примера большого приложения, где наследование использовалось бы только там, где это нужно — обязательно кто-то поленится и вместо поддержки интерфейса просто отнаследуется, а потом эту «архитектуру» приходится поддерживать.
UFO just landed and posted this here
> Потрясная кривая обучения
Было бы интересно посмотреть на эту кривую. Не могли бы Вы описать план курса по основам программирования на go?
очень классно было бы, если бы Вы попробовали научить кого-нибудь из младших братьев/сестёр (не своих, так друзей) и предоставили бы результаты «исследования»: в каких моментах именно go дети чаще ошибаются, что даётся сложнее/проще и тд
а так получается агитация и мало доказательств
О том, что опытный программист полностью осваивает Go, со всеми его подводными камнями, за несколько выходных, уже неоднократно говорили

А есть ли ссылки на подобный опыт «изучения за несколько выходных»?
Это бред. За несколько выходных можно начать писать на Go. А вот чтобы начать писать на нем «красиво» — нужно хотя бы месяца 3 на нем поработать. И да, подводных камней немного, но они есть и за несколько выходных их все не обойдешь.
Поясню почему спросил: я тот самый «опытный программист» (39 лет, проф. стаж 17 лет, общий стаж программирования 24 года), но вот от Go меня просто «воротит». Так что хотелось бы каких-то «success stories» про изучение Go в кратчайший сроки или что-то вроде того.
Сакцесс стори такие, что разработчики, которые никогда на Go не писавшие — начинают это делать через 3-7 дней после знакомства с языком. Они конечно не асы после этого, но работать с языком уже могут. Есть несколько компаний, которые переходят на Go, с подобным успешным опытом.
Хотелось бы поинтересоваться отчего вас воротит? И какой у вас бэкграунд языковой?
Оставим мою персону за рамками обсуждения. Меня интересует только:
О том, что опытный программист полностью осваивает Go… за несколько выходных, уже неоднократно говорили

Где говорили, ссылки, кто говорил, кто переходил?
Помнится, год назад автор так же восторженно восхвалял Qt, заявляя что всем срочно нужно прыгать на кресты.
Теперь вот Go.

Интересно, что будет дальше. Господа, сделаем ставки?
Экосистема слабовата имхо

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

Насколько сильно я вас заставлял переходить на Qt и кресты, в частности?
Теперь вот Go.

Повторяю предыдущий вопрос: заставлял ли я вас сейчас «прыгать» на Go?
ты должен пересесть со своих Java/Obj-C/.NET на мягкий и пушистый Qt.


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

Я считаю, что первый язык для обучения должен обладать следующими качествами:
1. Быть не слишком сложным (ну это очевидно). Поэтому C/C++ отпадают.
2. Но в то же время не слишком упрощенным, не «детским» — а пригодным для реальной коммерческой разработки. То есть учебный опыт должен быть не чисто игровым («а теперь забудьте всё, что учили раньше, сейчас мы займёмся нормальными вещами»), а практическим. Например, в наше время некоторых ещё учили на Бейсике, хотя он уже был полностью устаревшим и неактуальным. Поэтому же отпадают все слишком экзотические языки.
3. Обязательно быть типизированным. Учащийся должен хорошо различать различные структуры данных и понимать, что автоматическое приведение типов — это плюшка, а не данность. Не должно быть поначалу слишком много скрытой магии.
4. Обязательно иметь понятие указателя. Даже в нынешнюю эпоху сборщиков мусора учащийся должен получить базовое представление о работе с памятью, что происходит «под капотом», о передаче по ссылке/значению. Не сразу в хардкорной версии C++, но должен.
5. Быть процедурным, поскольку это самая простая, естественная и логичная идеология.

Так что да, Go — это очень хорошая кандидатура.
Go не процедурный все же. Есть и привязка методов к структурам и наследование через композицию.
Проблему инкапсуляции решили до безобразия интересно: все поля структуры, которые начинаются с символа верхнего регистра идут наружу, а все остальное остается внутри.

Это не «решили проблему инкапсуляции», это «придумали еще одну конвенцию». Это никак не отвечает на вопрос «какие поля надо прятать, а какие — нет» — который, собственно, является проблемой инкапсуляции.
Ты конечно же прав.

Конкретно в данном случае я имел ввиду под «проблемой» инкапсуляции то, что сходу сказать, можно использовать метод или нет, нельзя и был не очень прав, потому что это не проблема вовсе.
Лично я считаю, что лучшим обучающим языком программирования является Python, тут и REPL, и достаточная высокоуровневость позволяющая не задумываться об ньюансах реализации, концентрируясь на сути алгоритмов, и хорошая реализация различных парадигм программирования, более чем подходящаяя для введения в них, и громадное количество библиотек, которые позволят сразу решать интересные обучающемуся проблемы (начиная от игр, и заканчивая научными вычислениями, обработкой и визуализацией данных), ну и разумеется практическая применимость самого языка в широком спектре областей. Да, на его примере нельзя будет толком рассказать о компиляции в машинные коды, о статической типизации, и о многих других вещах, но, не думаю, что всё это больше технические детали, достойные углубленных курсов, нежели чем жизненно необходимые вещи для начинающих.

Презентация же Go как обучающего языка (и, например, как по-настоящему системного), на мой взгляд, это чистое натягивание ежа на ужа, которое будет делать языку больше вреда, чем пользы, ибо рекламируя язык в неподходящих областях, создаётся дурная репутация, которая будет автоматически распространяться и на области где этот язык чрезвычайно хорошо.
Я тут посмотрел перечень всех статей автора данной статьи и обнаружил одну интересную для меня вещь. Этому автору, оказывается, 16-17 лет отроду. Он школьник, даже не студент. Вот статья от 10-го мая 2013-го года, где он прямо говорит:
Меня зовут Илья Ковалевский, я ученик 8-Б класса киевского лицея

Так что относитесь к предложению о Go как лучшем языке для обучения как к личному опыту автора :)
Мне 16 лет, я действительно школьник и не в коем случае не студент, но когда я начал учить Go у меня уже было за плечами 3 года опыта работы с С++, из них 2 — в FOSS.
Хм… Мой пардон… Тогда снимаю свой, можно сказать, «наезд» на счет Паскаля. В вашем случае это вполне нормально, вы еще не профессиональный разработчик.

Пишите статьи от себя. Не надо пытаться выглядеть «крутым» разработчиком. Вы и так достаточно круты для своего уровня. Я, по крайней мере, в ваши годы не умел так хорошо излагать свои мысли…

В общем я с вами согласен. Go — хороший язык для изучения в качестве первого языка. Пока не дойдет до конкурентных вычислений. Там уже требуется иметь теоретический бэкграунд. Параллельные/многопоточные вычисления это отдельная дисциплина…
Главный же плюс Go, в отличие от того же Паскаля — это актуальность…
Черт, а тут я тут похоже облажался. Дело в том, что в С++ ссылка (reference) может указазывать только на один и тот же самый объект, а в случае с указателем (pointer) — это не так. Поэтому мне кажется, что указатель в Go это скорее ссылка, нежели указатель (в контексте С++, например). Я не прав?
поэтому мне кажется, что указатель в Go это скорее ссылка, нежели указатель (в контексте С++, например)

Т.е. вы хотите сказать, что в Go нет возможности изменить значение переменной, содержащей указатель?
Почему тогда следующий код работает:
package main
import "fmt"
 
func main() {
	x := 5
	y := 7
	p := &x
	fmt.Printf("%v\n", *p)
	p = &y
	fmt.Printf("%v\n", *p)
}
?
Все верно, я просто опять запутался в этих определениях. Да, все-таки указатели, пойду поправлю статью, спасибо!
А что в контексте замены обобщений называется «бутсрапингом»?
> Жестко? Еще бы! Но знаете, такая жесткость, она воспитывает!

Воспитывает что? Ненависть к программированию?
Сколько часов в школе программирование нынче, что на это времени не жалко?

> «а как наследовать два класса одновременно???»

А в Go проще что ли?

type Reader interface {
Read(p []byte) (n int, err error)
}

type ReaderInv interface {
Read(p []byte) (n int, err error) // Читаем в обратном порядке
}

type MultiReader struct {
Reader
ReaderInv
}

И, наконец, я хочу сделать как-то так:
switch t := t.(type) {
case Reader:
t.Read(...)
case ReaderInv:
t.Read(...)
case MultiReader:
t.Read(...)
}

думаете я получу предсказуемый результат? Только не надо говорить «а не надо так делать!», я на любом языке могу так не делать.
Что-то я не вижу, что бы проблемы с наследованием волшебным образом исчезли.
Sign up to leave a comment.

Articles

Change theme settings