
Комментарии 551
Категорически поддерживаю.
Сам являюсь преподавателем в it-ориентированном колледже. Веду шарпы у студентов 3 курса со специализацией .net. На первом курсе им давали питон и js , после чего некоторые не могут никак понять, на кой в коде всякие int и bool, как работает обычный for , почему они не могут сделать int a = console.readline() и тп. Надеюсь, в будущем смогу повлиять на программу.
Мне с минимальными знаниями по шарпу в свое время было легко вкатиться в js, но я даже представить себе не могу , какого труда бы мне это стоило, выстройся мой путь наоборот.
после чего некоторые не могут никак понять, на кой в коде всякие int и bool, как работает обычный for , почему они не могут сделать int a = console.readline() и тп
Что характерно, в общем-то они правы. Тут вопрос в том, что является целью образования: передача устоявшихся предрассудков или развитие когнитивных способностей.
А как, кстати, вы отвечаете на вопрос, на кой в коде int и bool? Для борьбы с ошибками? Так это сложно объяснить людям, которые до этого прекрасно обходились без них. Я своим студентам честно объясняю, что это религиозная традиция, возникшая во времена, когда так было проще написать эффективный транслятор, а также что некоторые люди считают, что это сильно помогает в борьбе с ошибками.
Все просто объясняется. Программирование основано на логике. Первый закон логики: иметь не одно значение — значит не иметь ни одного значения; если же у слов нет значений, тогда утрачена всякая возможность рассуждать друг с другом, а в действительности — и с самим собой; ибо невозможно ничего мыслить, если не мыслить что-нибудь одно. Статическая типизация это как раз "реализация" этого закона.
Эк вы глубоко копнули. Однако про типы переменных в этом законе ничего нет. А их значения единственны.
Однако про типы переменных в этом законе ничего нет
Ясен пень, этот закон Аристотель вывел.
Смысл в том, что должна быть определенность. int - базовый целочисленный тип; bool - это примитивный тип данных в программировании, который может принимать только два значения: истина и ложь; и т. д. Типы не равны друг другу, но можно преобразовывать из один в другой. Статическая типизация позволяет вам следить за корректностью хода ваших мыслей и сразу по рукам бить, если что не так. Динамическая типизация позволяет вам говнокодить и получать ошибки в рантайме.
Очень маловероятно, чтобы в реальной программе ошибка возникла бы именно на уровне несовместимости int с bool. Тут уж надо или формально выводить настоящие категориальные типы, как в Haskell или даже Coq, или не делать вид, что всё хорошо.
Я очень много программировал на Паскале в своей жизни (такое время было, когда это было модно), и в целом этот язык мне скорее нравился, но я не могу припомнить, чтобы система статической строгой типизации Паскаля когда-либо нашла мне реальную ошибку в программе, а не мнимую (то есть не сводящуюся к тому, что в этом месте по синтаксису нужно вставить явное преобразование типов).
Присваиваешь ты значение одной переменной другой переменной. Первая 32 бита, вторая 64. Всё присваивается и работает пока во вторую не запишут значение, которое не влезет в первую. А компилятор на этапе компиляции тебе уже даст подсказку, что может такая ситуация случиться.
Для чего вообще в языке программирования высокого уровня нужны два разных типа целых? Выглядит как решение проблемы, которой в принципе не должно существовать.
В бизесовых приложениях чаще делают ошибки другого рода. Например, когда пользователь вводит невалидный номер телефона, или пытается списать с баланса склада больше, чем там лежит.
Два? Обычно их гораздо больше.
Идея автоматизировать выбор формата данных - понятна (полезность для обучения пока отставим). Но приводит к огромному оверхеду из-за избыточности (как неотменяемая длинная арифметика в Python). И к постоянным перекодировкам, со всеми вытекающими и по производительности, и по надёжности.
Это действительно нужно для учёного языка? По-моему важнее интерактивность, релевантный набор абстракций изучаемым темам. Доступный API, интроспекция, чтобы абстракцию можно было крутить и разбирать на части как игрушку. А также адекватные, объясняющие сообщения об ошибках.
Я не фанат, но в том же питоне есть целые в смысле математики, и ctypes для работы с С-подобными структурами. В этом конструкторе подкупает возможность интерактивно "пощупать" и арифметику с фиксированной разряднотстью, и размеры структур и их отдельных полей, и работу с указателями и т.п. Можно поиграться с выравниванием, endian, и прочими прелестями, которые обычно зашиты в дебрях компиляторов и доступны в ощущениях разве что через дисассемблер. Синтаксис, правда, местами своеобразный.
Про действительно ли нужно сразу вводить разные целые типы данных - дискуссионный вопрос, но могу по опыту сказать, что это точно можно, и не создаёт заметной ступеньки в обучении. Н сильно сложнее, чем просто концепция типов данных. Может даже помочь пониманию.
А вообще - было бы прикольно чери-пикать отдельные дизайн-решения из разных языков, жаль что такого нет.
ну вот как понадобится это число сохранить, к примеру, в БД, так сразу голова начнет работать, что выбрать. Можно вообще в строку перевести, по идее.
База, кстати, здесь не самый удачный пример: на границе слоев должен быть полноценный парсинг входящих данных, в рантайме, а не статический тайпчекинг. Мы же не знаем что там снаружи к нам прилетит.
Часто так и есть. Навороты, типа LINQ, могут скрывать от работчика подобные нюансы, реализуя парсинг за сценой - показывая в коде лишь переменные да типы. Это удобно, не спорю. Но у новичка такие неявности могут создать обманчивое впечатление, будто за него все ошибки ловит компилятор.
Не обязательно в бд. Как только начинаешь работать со сторонними сервисами, файлами, приложениями и памятью, так может оказаться, что твой универсальный тип переменной туда не подходит и нужно брать конкретные типы, которые учитывал писатель стороннего приложения. В делфи есть тип variant - бери и пихай туда что угодно, но тогда как раз и всплывают те накладные расходы, которые будут каждый раз определять, а что у нас содержится в переменной и как с этим работать.
Как минимум для того, что один тип требует для хранения в два раза меньше памяти, чем другой. Представим обычную картинку. Чтобы её хранить, каждая точка в ней кодируется 4 байтами - RGB + альфа-канал. По вашей логике зачем использовать там целочисленный байт - давайте сразу брать UInt64. И размер нашей картинки вырастет в 8 раз. Это как пример и таких примеров огромное количество.
А при чём тут неверный пользовательский ввод вообще непонятно - такие задачи решаются через регулярные выражения. Это вообще разные типы ошибок.
Как минимум для того, что один тип требует для хранения в два раза меньше памяти, чем другой.
Думаю, что эта тема была близка каждому во времена Вирта, где всем должно было хватать 640Кб . Но сейчас она мне кажется скорее специфичной.
Ни в коем случае не умоляю важности понимания того как информация кодируется и представляется в компьютере, и откуда в программах берутся ошибки переполнения. Но это вряд-ли то, обо что нужно вынуждать каждый раз спотыкаться на протяжении всего курса обучения.
представляете, если все картинки вмиг вырастут в объеме в 8 раз. Этот объем для записи потребует в 8 раз больше времени. А если у вас тысяча фоточек. Раньше вы их за минуту копировали, а сейчас за 8. И это мы только про фоточки. А еще винда потяжелеет, весь код, базы данных, голос по мобильной сети передать тоже дольше. Эти числа - они везде, не только в картинках. Контрольный: уже не RTX 5070ti с 16 гигами GDDR7 памятью надо, а 128 гигов GDDR7. Интересно, сколько такая карточка стоить будет...
Сейчас в нейросетях часто используется тип fp16 для экономии памяти, а тут такое предложение отказаться от 32 битных переменных
Я считаю, что вы могли бы здесь показать сильные аргументы с позиций обучения. Однако в качестве примеров почему-то приводите задачи ввода-вывода, где статическая типизация не имеет существенного значения. Вы же не предлагаете на самом деле раскидывать нюансы работы с внешним миром по всей программе, вместо того чтобы обучать отрабатывать сериализацию/десериализацию данных на границах слоев?
Можно, конечно, сделать числа в языке только одного типа, условно, хранить как строки произвольной длины. И использовать длинную арифметику для работы с ними. Со всем сопутствующим оверхедом.
Насколько программы замедлятся из-за этого - неясно. Полагаю что существенно.
Ну питон и некоторые другие языки так работают.
Это была попытка донести аргумент, что в итоге программы выполняются не в мире концепций, а на реальном железе, у которого есть железные же ограничения.
Работать с числами в строковом представлении можно, но для процессора придется все-таки их переводить в те представления чисел, которые поддерживаются в архитектуре вычислений этого процессора.
И все это придется делать за счет дополнительных приседаний, которых можно попытаться избежать, если в языке есть типы данных, нативные для оборудования.
Конечно, но надо смотреть, когда и насколько это оправдано.
Для сложных вычислительных задач, когда надо выжимать последние наносекунды из обработки чисел, конечно, надо использовать адекватное машинное представление. Но там и Фортран выучить бы заодно неплохо.
А в рядовой повседневной практике арифметика неограниченной точности может быть вполне оправдана.
Зачем вам числа в языке только одного типа? От языка требуется возможность определять свои domain-specific абстракции, а не спотыкаться постоянно о встроенные машино-специфичные типы.
Если работаешь с цветами, то практичнее определить тип Color с нужным набором операций, оставив нюансы низкоуровневого представления за кадром. Среди этих операций наверняка будет работа с цветовыми пространствами, масками, отдельными компонентами. А вот деления или взятия корня n-й степени быть не должно, поскольку они здесь не имеют смысла.
Как находить и строить подходящие абстракции для предметной области, - вот этому искусству нужно учиться, - а не таскать специфику упаковки данных в памяти через все приложение. Я серьёзно не вижу повода для гордости от того, что в языке высокого уровня, машино-специфичные типы выставлены наружу на уровне языка. Все это может и должно жить в библиотеке.
Интересная мысль.
Зачем вам числа в языке только одного типа?
Вроде бы я и не настаивал, что числа должны быть абстрактно-универсальными.
Я как раз за то, чтобы не забывать, глядя на небоскребы, что в основе все-таки конкретные сталь и бетон, а не некий универсальный "строительный материал" знания о котором строителям этих небоскребов не важны.
От языка требуется возможность определять свои domain-specific абстракции
Вроде бы никто и не мешает определять. Просто не на уровне самого языка, а пользуясь им. На то это и язык.
а не спотыкаться постоянно о встроенные машино-специфичные типы.
Не могу припомнить языки явно страдающие от поддержки встроенных типов. Но может такие и есть, просто я не в курсе.
Если работаешь с цветами, то практичнее определить тип Color с нужным набором операций, оставив нюансы низкоуровневого представления за кадром.
На мой взгляд "работа с цветом", "работа с документами", "работа с авиабилетами" это не задача языка. Это задачи конкретных библиотек/фреймворков.
Например, есть задача "описать вкус кофе".
На русском языке можно миллионом разных способов описать вкус кофе, который вы выпили на завтрак.
Сам язык при этом не имеет средств для истинной передачи вкуса, чтобы читатель ощутил ровно то же, что и вы.
Однако это не мешает пользоваться языком для описания вкуса, причем так, что читатель поймет что же писатель хотел до него донести.
Так же и на языках программирования высокого уровня можно описать нужные алгоритмы и при этом не требуется, чтобы язык поддерживал именно этот конкретный алгоритм или именно под него был разработан.
Все это может и должно жить в библиотеке.
Предметные домены, предметные же типы данных и связанные со всем этим абстрации должны жить в библиотеках, соглашусь.
Возможно, кстати, что вы видите какую-то принципиальную проблему в языках с определенными типами, но от меня эта проблема как-то ускользает.
Однако в качестве примеров почему-то приводите задачи ввода-вывода, где статическая типизация не имеет существенного значения. Вы же не предлагаете на самом деле раскидывать нюансы работы с внешним миром по всей программе, вместо того чтобы обучать отрабатывать сериализацию/десериализацию данных на границах слоев?
Статическая типизация как раз помогает доказать убедиться, что на границах слоя сериализация/десериализация была выполнена, и что все части слоя согласны с тем, что именно должно было быть (де)сериализовано.
А потом мы получаем приложения вроде ардуино иде на 200 мегабайт и к нему накладных библиотек ещё в полтора раза больше. А что, удобно же писать на фреймворках, писанных на фреймворках, можно не заморачиваться о памяти. Ну, не будет приложуха на диск влазить, купите новый диск. Теперь в оперативу не влазит? Вот новая в магазине нидорага. Что, нужна новая материнка, проц, блок питания? Зачем этот архаизм, берите макбук за 300к и не парьтесь.
Ещё можно все кушать ложкой, непонятно, зачем вообще вилки тогда придумали?
Большая часть человечества вообще кушает палочками, так что аналогия не очень ясно просматривается.
Из аналогии с ложками и палочками, на самом деле, много выводов можно сделать, если вы не будете останавливаться в анализе аналогий.
Ключевой вывод в том, что человек, предложивший единственный числовой тип, только-только проникся идеей безусловной фиксированной размерности, и, естественно, имея в руках такой молоток, горит желанием видеть вокруг гвозди.
Где-то эта идея идея полезна, если значимое снижение когнитивной сложности оправдывает последствия роста потребления ресурсов, но как будто бы единственный числовой тип - это не тот случай, как выше уже любезно объяснили.
Как для чего… так работают транзисторы. У них два состояния, что волшебным образом соврадает с булевой математикой, что в свою очередь дает возможность производить более сложные математичсекие вычисления.
Языки программирования создавали из этих соображений и ограниченности вычислительных способностей современности. Потом в девяностых назрела концепция абстрагирования, так сказать, ибо индустрия железа сильно стрельнула. Плюс интернет появился. Независимые академики поспользовались железной рефолюцией и придумали не мало полезных вещей, языков программирования, ядер операционных систем…
Никто не виноват и все виноваты одновременно.
Очень маловероятно, чтобы в реальной программе ошибка возникла бы именно на уровне несовместимости int с bool.
Ахаха. Пресловутый аппарат Therac. Одно из решений: uint8 кастовался в bool - ничего страшного, да. Все так делают. Но в другом месте он инкрементировался, и иногда переполнялся.
Если он именно кастовался, то статическая типизация ничем не помогла. А вот динамическая, кстати, помогла бы в момент первого инкремента.
Так что ваш аргумент играет против того, что вы, по всей видимости, хотели им доказать.
Странные вещи пишете. У меня были в реальной программе ошибки на уровне несовместимости bool и boolean и ByteBool. Разница в размере переменной, и она в том месте была неочевидна. То есть программа прекрасно работала до тех пор, пока перед внесениием в булевую переменную не происходило каких-то других действий. Стоило сложить пару чисел выше и всё, байты съезжали и переменная ломалась. Да, там работа была через указатели. При этом программа прекрасно работала некоторое время, пока не понадобилось добавить какую-то мелочь.
Я именно про это и написал - самому себе созданные сложности, лечащиеся прямым кастингом.
Если бы, допустим, язык программирования, на котором вы писали свою программу, имел бы динамическую типизацию, то переменные автоматически предоставляли бы значениям столько памяти, сколько им нужно.
иметь не одно значение — значит
…быть функцией не A → B, а A → 𝒫B.
Вы не подумайте, я не против статической типизации, а очень даже за. Кстати, скажите, если у переменной xs тип Vect n Int (n — число), а ys : Vect m Int, то какой тип у конкатенации xs и ys — Vect (n + m) Int или Vect (m + n) Int? В ряде теорий это два разных типа.
Во-первых, в контексте int a = 10; я им объясняю, что в данном случае мы объявляем переменную, а дальше ею пользуемся, т.е. она существует в зоне видимости с этого момента, а не взялась хрен пойми откуда.
Во-вторых, хоть сам я предпочитаю var, я смиряюсь с тем, что ревьювить код с явным типом гораздо проще.
В-третьих, в контексте int sum(int a, int b) я им объясняю, что таким образом мы явно говорим, что ждем на вход, и что гарантированно будет на выходе. Это и читаемость повышает, и документирует код. Отсутствие этих "архаизмов" удобно только на примитивных примерах, а вот когда надо вспомнить, как пользоваться какой нибудь библиотечной функцией, или функцией, написанной коллегой, тут типизация упрощает понимание.
Даже условное T func<T, R>(T first, R second, R third) понятнее, чем func(a, b, c)
В-четвертых, аргумент про ошибки как вопрос "где вы были 8 лет " - все высмеивают, но никто так и не ответил. Мне при работе с шарпом ни разу не приходилось решать ошибки, возникающие из-за неправильного написания функции, а вот в js-e неоднократно.
В-пятых, я не ругаю жс и питон, но считаю, что они создают ошибочное представление в неокрепших умах и не позволяют сразу воспитать системное мышление.
Например, у некоторых студентов вызывал ступор вызов console.WriteLine, когда им надо было вывести несколько значений. Они писали console.writeline(a, b, c) ожидая трёх выводов, а получают один. Им реально тяжело понять, что у функций разные сигнатуры, они привыкли к магическому print, который съест любую бездумную писанину
Последний аргумент несколько напоминает “Господь страдал, и нам велел". Почему магическому? Просто обычная функция с параметрическим полиморфизмом и переменным количеством параметров. Допустим, print переписать в три вызова будет несложно, но с max или min придётся уже помучаться.
Истинная причина в данном случае состоит в том, что либо в языке не поддерживаются функции с переменным количеством параметров, либо авторам стандартной библиотеки было лень удобно реализовать конкретно функцию print. Ничего дисциплинирующего мышление я в том и другом случае не вижу.
Вся беда таких способов преподавания - это в создании иллюзии будто код пишется для машины.
Написание кода для машин уже давно ушло в прошлое, вместе с ассемблером и плюсовиками, с патологическим стремлением хвастаться кодом на бумажном листочке.
Пайтон идеален для обучения по множеству причин. Однако параллельно дружелюбному пайтону с кучей "магии" так же нужен и старый добрый си, дабы понять что всё это работает весьма чётко и логично, хотя и умеет причинять боль из за строгости логики и "сайд эффектов" низкого уровня.
А на счёт магического "print" - порочная практика использовать вывод в консоль в целом. Есть логгеры, есть return, и есть дебаггер. А пользоваться Console.WriteLine в коде - та самая проблема из разряда "зачем нужны типы данных" или "зачем нужен логгер"
в создании иллюзии будто код пишется для машины.
Э... А для кого тогда пишется код, если не для машины?
Для человека. Чтобы тот мог понять, что за магия тут происходит. Для машины есть ассемблер.
Для человека.
Но выполнять этот код вряд ли будет человек, все-таки.
Чтобы тот мог понять, что за магия тут происходит.
Если ИИ ассистент сам написал код, сам его запустил и сам обработал результат, то получается, что вообще нет человека, для которого этот код был написан с замыслом "чтобы человек мог понять".
А код, который "для человека", есть. Странно.
Для машины есть ассемблер.
А есть люди, кто пишут код на ассемблере. И тут непонятно, получается, для кого они пишут.
Но выполнять этот код вряд ли будет человек, все-таки.
Конечно. Компилятор, интерпретатор, sql-сервер.. Человек нужен, чтобы через год что то в том коде понять и поменять при необходимости.
Если ваш ИИ лабает неподдерживаемый write only код - неважно, на python оно или на brainfuck.
Если ваш ИИ лабает неподдерживаемый write only код - неважно, на python оно или на brainfuck.
Абсолютно верно. Неважно на чем написан код.
Важно что код этот: а) есть, б) человек его читать не будет.
И поэтому утверждение, что "код для человека пишется" не всегда истинно, т.к. в данном случае нет этого самого человека.
Так вот именно - код пишется для человека, чтобы он мог его читать. Но читать тоже нужно учиться.
Приведу с позволения аналогию: когда вы учите английский язык, вы следуете всем правилам построения предложений и произношения слов, и только после начинаете постигать разговорную речь с ее упрощениями, ведь только тогда вы будете понимать, что стоит за упрощением, и сможете объясниться при любых обстоятельствах. Плюс понимая принципы работы английского языка, будет легче вникать в принципы построения других соседствующих языков. Если вы сразу начали с разговорной речи и, как следствие, разговариваете как гастарбайтер, откуда глубинному пониманию взяться?
И я тоже считаю, что в современных реалиях языки типа плюсов это оверхед - Шарп/жаба/го вполне достаточно
Приведу с позволения аналогию: когда вы учите английский язык, вы следуете всем правилам построения предложений и произношения слов, и только после начинаете постигать разговорную речь с ее упрощениями
Верно для английского, неверно для китайского.
Таким китайским среди языков программирования является C++. Большинство его особенностей невыводимо ни из каких общих соображений. Разница в том, что китайцам, чтобы дойти до такого состояния дел, понадобилось 8000 лет (с их слов), а Страуструп справился за 50.
Естественные языки к способам кодирования алгоритмов относятся скорее никак.
В китайском языке очень простая грамматика. Он куда больше напоминает Лисп, чем С++.
Грамматика-то простая, но в практическом плане это ничего не даёт. Надо просто знать, что 您贵姓 – это вопрос, а 马马虎虎 – поучительная история про художника. Не говоря про сами знаки.
Итак, дети, вот пример простой грамматики, интуитивно понятной:
A:=1
А вот пример сложной и непонятной грамматики:
A=1;
Не перепутайте.
При этом во всей математике детишки знают знак равно как тождество, а не как знак передачи (присвоение) значения.
Это идиомы, а не грамматика. Идиомы есть в любом языке.
Грамматика - это к примеру образование прошлого или совершенного времени. В китайском после глагола ставится лишний слог, в индоевропейских языках это целая морока.
Но ведь дети учат язык как раз из разговоров, а грамматику осваивают потом, с трудом и не все.
Это не иллюзия, код так то по прежнему пишется для машины.
Просто не в первую очередь.
Эта религиозная традиция работает в python и js так же, как и в других языках, просто замазана и скрыта (что приводит к значительным проблемам и обмазыванию тестами).
Концепция типов фундаментальна и, в общем то, довольно проста - разные данные хранятся по разному, арифметические операции нельзя осуществлять с почтовыми адресами.
Вы сейчас говорите о типах значений. А статическая типизация заключается в том, что типы присваиваются не только значениям, но и переменным. И это никак не влияет на возможность или невозможность осуществления арифметических операций с почтовыми адресами.
Языки PL/I и Cobol статически типизированные, но там можно прибавить единицу к почтовому адресу (точнее, попытаться это сделать). Языки Lisp и Scheme (и Лого) динамически типизированные, но там нельзя прибавить единицу к почтовому адресу.
Да, но фундаментально тут то, что типы данных существуют, они важны, для их преобразования используются специальные операции. Это не религиозная концепция, этому нужно учить. В Python так то тоже нельзя сложить строку с числом.
Динамическая типизация же, особенно слабая, лишь скрывает это.
Это и есть то, чего хочется решить.
Это так же важно и для промышленного программирования - пусть когда то js и python сделали динамическую типизацию привлекательной фичей, сейчас куча людей пытаются решить проблемы, вызванные этим решением. TS как и аннотации типов в python придуманы не просто так.
Типы данных, безусловно, существуют и находятся в фундаменте программирования (по крайней мере, два типа: атом и список). Я вовсе не имел в виду, что сами типы данных являются религиозной концепцией. Религиозной традицией я назвал декларации типов переменных.
На этот вопрос можно смотреть с разных точек зрения. Вы вот привели аргумент, что динамическая типизация скрывает наличие типов данных. С моей точки зрения, скорее статическая типизация скрывает тот факт, что типы присущи самим данным, а не (не только) переменным.
Более того, статическая типизация – это шаг к нестрогой типизации, то есть к неявным преобразованиям типов. Даже в Паскале целые разной длины неявно преобразуются друг к другу и к вещественным. Про C/C++ нечего и говорить. И это (потеря разрядов и расширение знака в результате присваивания переменной совместимого типа), на мой взгляд, гораздо более реальная проблема, чем мифическая запись bool в int.
Я всегда специально обращаю внимание студентов, что оператор присваивания в статических языках включает в себя шаг преобразования типа справа налево, в то время как в динамических языках присваивание не имеет такой семантики.
TS как и аннотации типов в python придуманы не просто так.
Реальная востребованность их, как видим, невелика.
Ну как не имеет, а JS?
Ну то есть при присвоении безусловно нечему приводиться, но при использовании значения JS выдает самый безумный список неявных преобразований, которые нужно знать. Собственно самые страшные вещи в js, это неявные преобразования строк в числа и обратно, потому что они нетранзитивны (не все строки это корректные числа) из-за чего их нужно постоянно валидировать при пользовательском вводе.
Да и python сложение float и int вполне себе проводит с результатом в виде float
C это отдельная вселенная, это безусловно не лучший учебный язык, в том числе из-за UB, а вот в других статических языках обычно неявные преобразования работают только для неразрушающих преобразований, что работает довольно прозрачно.
Безусловно типы имеют данные, а переменные - лишь их абстракции.
И только вам (пользователям языков в смысле) решать, какую абстракцию вы считаете менее протекающей - когда коробочка имеет форму или когда вместо коробочки наклеечка.
Как по мне статическая валидация - штука удобная и для пользователя и для компилятора.
Она позволяет выразительно описывать API (какие данные требуются функции), предотвращает множество тупейших ошибок с переиспользованием идентификаторов для разных (в контексте программы) сущностей и исключает целые классы ошибок валидации инвариантов, поскольку оные производятся на этапе компиляции и их никак нельзя проигнорировать.
Динамические ЯП используют целую гору костылей типа стат анализа и автотестов для того, что работает почти бесплатно. Лишь ради возможности использовать другую, более простую, как им кажется, абстракцию идентификаторов.
Неявные преобразования типов в js я, конечно, не одобряю (особенно известную фишку с конкатенацией-сложением), однако это не является аргументом против динамической типизации, как таковой.
Так же как и против статической. Они слегка ортогональны.
Основное отличие - ты указываешь тип и потом живешь с этим ограничением. Или не указываешь тип, а получаешь его рантайм и живешь без ограничений.
Второе проще примерно на 1 ключевое слово в начале для каждой переменной и поля, но сложнее в неопределенном количестве мест, где ты не можешь определить необходимые данные по сигнатуре функции или понять что происходит лишь по идентификатору
Второе позволяет параметрический полиморфизм и универсальные контейнеры, что в некоторых приложениях очень упрощает жизнь.
Функция в динамическом языке не обязана знать, с чем она работает. Например, можно написать (и скомпилировать) сортировку элементов ещё неизвестного типа (так работает библиотечная функция sort).
Универсальные контейнеры и обобщенные функции вполне себе есть и в статически типизируемых языках (generics).
И просто как забавный факт, вы удивитесь, что стало с функцией sort в последней версии Python.
Для генерика тип параметра должен быть указан в момент его компиляции. Это не всегда возможно.
А что там у питона?
Предположу, что ситуации, когда не возможно определить тип элементов коллекции довольно далеко от обучения программированию.
А в Питоне меня в своё время поразил переход на key-functions вместо компаратора (ну или интерфейса Comparable, если бы такое там было).
Предположу, что ситуации, когда не возможно определить тип элементов коллекции довольно далеко от обучения программированию.
Тут возникла некоторая путаница в изложении. Конечно, нетривиальные случаи выходят за рамки обычного обучения. Однако тут приводился аргумент, что обучение динамическому языку плохо, потому что в коммерческой практике динамические языки плохи. И вот это утверждение сомнительно как в своём обосновании, так и в причинно-следственной связке.
А в Питоне меня в своё время поразил переход на key-functions вместо компаратора (ну или интерфейса Comparable, если бы такое там было).
Это действительно очень странно. Безусловно, в Питоне много странных вещей. Начиная с отступов.
Это действительно очень странно. Безусловно, в Питоне много странных вещей. Начиная с отступов.
Да-да. Старая добрая мантра про отступы. «Вот здесь я зареджектил пул реквест, потому что в .cxx форматирование кто в лес, кто по дрова, указал автору на расположение файла стилей для подключения к редактору кода. А вот здесь мне пришлось оформить небольшой скрипт на рутнопе, и знаете что? Случился бархат от того, что там оформление требуется в силу синтаксиса! Ну вы подумайте только, как они смеют требовать от меня оформлять код не в бомжатском стиле!»
Что касается key functions, то вообще ничего странного: всего лишь опциональный хелпер для уточнения конкретной реализации Comparable во время сортировки. Например, тапл сам по себе Comparable (реализует протокол сравнения двух экземпляров), но, как указано прямо в документации, иногда требуется уточнить, что в сортировке необходимо использовать Comparable от другой сущности: в простейшем случае — от конкретного элемента тапла, а не от всего тапла, в сложных случаях можно прямо на ходу строить экземпляры Comparable от текущего элемента; ограничений никаких.
Так для этого и передавали бы в сортировку функцию сравнения, как нормальные люди, а не заставляли решать на порядок более сложную и, главное, не относящуюся к делу задачу генерации ключа.
Так для этого и передавали бы в сортировку функцию сравнения, как нормальные люди, а не заставляли решать на порядок более сложную и, главное, не относящуюся к делу задачу генерации ключа.
В питоне ходить вглубь структур это относительно дорогое удовольствие. Компаратор приходится дергать на каждом шаге сортировки. Если при этом он ещё ходит вглубь элементов - чтобы доставать значения по которым нужно сортировать (а иначе зачем он вообще был бы нужен), - то получается накладно.
Гораздо эффективнее сначала достать все значения за один проход, а уже потом сортировать получившийся "плоский" список. Для этого и нужна key func https://en.wikipedia.org/wiki/Schwartzian_transform .
В py2 функции сортировки принимали компаратор, но в py3 опцию выпилили, чтобы народ использовал более эффективный паттерн.
Так себе логика, потому что коль скоро у нас значения устроены сложно (а иначе зачем нам компаратор?), то их сравнение может потребовать многих шагов. Допустим, сначала сравниваем фамилию, потом, если фамилия одинаковая – имя, потом – отчество, потом – дату рождения, и т.д. Сэкономив в log(n) раз на вызовах компаратора, теряем в столько раз, сколько полей в структуре, на опросе ненужных скорее всего полей (так как скорее всего сравнение ограничится фамилией). И ещё на вычислении самого ключа, которое тоже не бесплатно по времени и памяти. Асимптотически, конечно, это выгодно при n→∞, но в реальных условиях – далеко не факт.
Это называется преждевременной оптимизацией.
P.S. Так ведь даже сходу и не сообразишь, как правильно построить ключ для ФИО без ограничения длины.
Так ведь даже сходу и не сообразишь, как правильно построить ключ для ФИО без ограничения длины.
Определить компаратор), и превратить в key: https://docs.python.org/3/library/functools.html#functools.cmp_to_key.
Эта функция, скорее всего, возвращает каррированный по одному из аргументов компаратор в качестве метода сравнения ключа. И таким образом ничего не оптимизирует.
каррированный по одному из аргументов компаратор в качестве метода сравнения ключа
Технически это сделано не совсем так, но суть вы уловили верно. У них есть статья, где довольно подробно описан подход https://docs.python.org/3/howto/sorting.html.
Это называется преждевременной оптимизацией.
Ну нет, скорее аргумент был что обучение типам важно, потому что это важная концепция, которую нужно понять при обучении.
А то, что и в промышленных ЯП это часто используется - другой вопрос.
Так то python и JS очень популярные ЯП
Для генерика тип параметра должен быть указан в момент его компиляции. Это не всегда возможно.
Не понял. Можно пример?
Пример чего? Когда не всегда возможно? Сортировка.
А что с ней?
sort : Ord a ⇒ [a] → [a]Я могу скомпилировать модуль, определяющий эту функцию, без знания конкретного типа.
Я могу скомпилировать другой модуль, скажем,
slowPartialMax : Ord a ⇒ [a] → a
slowPartialMax = head . reverse . sortтоже без каких-либо конкретных типов.
Если вы компилируете код с дженериком и не определяете тип, т.е. не используете по сути дженерик - он не компилируется вообще.
Не обязательно. Модуль, определяющий дженерик, может скомпилироваться без конкретных типов для дженерика, который будет использоваться потом отдельно где-нибудь в другом модуле.
Дженерик сам по себе не является самодостаточным объектом. Его нет смысла компилировать, если он не используется. Под компиляцией я понимаю конечный машинный код, а не промежуточное двоичное представление исходного кода.
Пустой дженерик никогда не попадет в конечный исполнительный файл.
На дженерик задается ограничение ведь.
Интерфейс/класс. Можно и без, но тогда и использовать их можно только как произвольный тип.
Реальная востребованность их, как видим, невелика.
Я вижу TS как стандарт веб-разработки, 80 миллионов скачиваний на npm со мной согласятся. Так что ещё раз пожалуйста, где вы видите, что востребованность TS невелика? Или вы просто не понимаете, о чём говорите?
Согласно TIOBE, интерес к TS более чем на порядок меньше, чем к JS.
TIOBE считается по количеству запросов в поисковик. Их, очевидно, будет больше про js, поскольку ts не добавляет почти ничего кроме типов. Опрос stackoverflow тут гораздо репрезентативнее
Религиозной традицией я назвал декларации типов переменных.
А почему вы смешиваете отсутствие типизации (нет, я никогда не буду в серьёзных разговорах использовать оксюморон «динамическая типизация») и неявную типизацию?
Более того, статическая типизация – это шаг к нестрогой типизации, то есть к неявным преобразованиям типов. Даже в Паскале
Паскаль у нас теперь образец языка с сильной и выразительной системой типов?
Реальная востребованность их, как видим, невелика.
Ну куда уж TS и mypy до Lisp и Scheme, понятное дело.
А почему вы смешиваете отсутствие типизации (нет, я никогда не буду в серьёзных разговорах использовать оксюморон «динамическая типизация») и неявную типизацию?
Я вроде не смешивал.
Паскаль у нас теперь образец языка с сильной и выразительной системой типов?
Нет, Паскаль образец языка с полумерами в отношении системы типов, которые и в смысле контроля ничего особенного не дают, и лишнюю писанину делать заставляют.
Реальная востребованность их, как видим, невелика.
Ну куда уж TS и mypy до Lisp и Scheme, понятное дело.
До JS и CPython.
Я вроде не смешивал.
Ну отлично. Тогда ML-стайл вывод типов вам норм?
Нет, Паскаль образец языка с полумерами в отношении системы типов, которые и в смысле контроля ничего особенного не дают, и лишнюю писанину делать заставляют.
О, здесь мы согласны. Но из этого есть простой вывод: не надо рассматривать паскаль (а не «не надо рассматривать статическую типизацию»).
До JS и CPython.
У меня есть разные знакомые, работающие в веб-экосистеме, причём в компаниях от местных консалтинг-бодишопов на три боди до фаанга, и если судить по их рассказам, то проектов на чистом JS, без тайпскрипта, не встречалось уже очень давно.
Другое дело, что в части проектов на TS половина типов — any, но это, гм, другое дело.
ML-стайл вывод типов мне норм. Другое дело, что он не ко всем проектам подходит (я вот, например, сегодня добавил поддержку нового обрабатываемого типа данных в выполняющуюся программу прямо на ходу, не останавливая её), но по крайней мере он имеет отчётливый смысл и в ряде случаев полезен.
Другое дело, что он не ко всем проектам подходит (я вот, например, сегодня добавил поддержку нового обрабатываемого типа данных в выполняющуюся программу прямо на ходу, не останавливая её)
Мне как-то (не) везёт писать такой код, где между мной и продом либо несколько слоёв стейджинга, либо это вообще библиотеки и вещи уровня «тайпчекер и интерпретатор для языка смарт-контрактов», где «менять программу при выполнении» не имеет особого прикладного смысла.
Поэтому, короче, я не могу эффективно спорить на этой территории за отсутствием наработанных паттернов. Какой тип добавили? Зачем? В чём конкретно это добавление выражается? Где бы вы упёрлись в выразительном статически типизированном языке? ХЗ.
Работает система управления оборудованием. Понадобилось поддержать устройство, работающее с новым для неё типом обрабатываемой информации. А останавливать программу ради этого совершенно не хочется, потому что целый комплекс технологических мероприятий. А так –модифицировал список обрабатываемых типов и подгрузил. Когда до них дойдёт дело при исполнении, они будут задействованы.
А упёрся бы я в противном случае в необходимость связной компиляции и вытекающего из этого перезапуска исполняемого модуля.
Что значит «новый тип»? Какие типы были, и какой тип — новый?
Да какая разница? Просто некая новая интерпретация последовательности байтов, образующей внутреннее представление. Например, пусть это будет 6-байтовое целое со знаком. Или строка иероглифов в кодировке GB2312. Или какая-то структура данных. Да неважно что.
Исходно у нас в компьютере есть только массивы байтов, представляющие собой содержимое оперативной памяти и всяких там блоков ввода-вывода. А нам нужно из них выделять какие-то имеющие прикладную семантику значения и с ними работать.
Вы о репрезентации, а я как раз о семантике. Что именно было нового в этой семантике?
Какая разница, что именно? Всё, что будет нового в семантике, мы можем синтаксически дописать кодом обработчика. В самом коде никакой семантики же нет, это мы его условно наделяем семантической интерпретацией.
Разница такая, что я не могу абстрактные метаконцепции переложить в код, нужны какие-то конкретные примеры, чтобы поиграться.
Но пока что выглядит так, что всё ещё у вас там просто добавился один из вариантов вокруг уже имеющейся семантики, и это вполне выразимо в достаточно мощных статически типизированных языках.
Тут фишка в том, что предметом нашего программирования в данном случае является как раз метаконцепция. В том числе автоматические преобразования семантики. А каждый конкретный пример, конечно, реализуем и другими способами.
Если очень схематично и не вполне точно, то представьте себе компилятор, который постоянно сам себя компилирует и дописывает, по ходу дела компилируя и другие коды на усложняющемся входном языке.
Понятно, что в таком деле по сути нет ничего, кроме символов.
Не уверен, что к месту, но в Java есть OSGI. Если новый тип имплементит старый интерфейс, вполне может прокатить.
Языки Lisp и Scheme (и Лого) динамически типизированные, но там нельзя прибавить единицу к почтовому адресу.
Когда именно я узна́ю, что я где-то случайно попытался прибавить единицу к почтовому адресу?
Когда попробуете. Это ж динамическая типизация.
Ну так это ключевой момент.
Я хочу знать, что написал ерунду, ещё до деплоя в прод (в идеале — вот прям когда я пишу конкретно эту строку, прям в IDE), а не в три часа ночи оповещением с прода, что ровно здесь случилась редкая комбинация условий, которая пошла по тому бранчу, который привёл к прибавлению единицы к адресу.
Я Ваши повадки хорошо знаю и оспаривать их не собираюсь, но согласитесь, что сама по себе невозможность присвоить паскалевской переменной типа integer значения типа boolean никак Вас к вашей цели не приблизит.
Если выкинуть из вашей фразы слово «паскалевской», то не соглашусь: приблизит.
В какой версии буста там STRONG_TYPEDEF появилось? Судя по копирайту в хедере (2002-й год) — рано появилось, может, даже раньше boost.lambda и всего такого. Надо, наверное, зачем-то людям разделять типы, чтобы неявных преобразований и ошибочных присваиваний не было.
Когда вы откроете реальный промышленный код, то там в 80% случаев внизу вообще всего будет один и тот же тип int без всякого STRONG_TYPEDEF.
Когда я открываю реальный промышленный код на хаскеле, то там нормально всё с newtype.
На плюсах, в принципе, тоже. Правда, когда я собеседуюсь на приплюснутого ассенизатора, то при написании кода на интервью я вполне себе говорю (и пишу) о типобезопасности и смотрю на реакцию интервьювера, поэтому у меня тут не совсем репрезентативная выборка.
Это, конечно, отсылка к личному опыту и вообще немного выпендрёж, но по-другому отвечать на тезисы «в реальном продакшен-коде не используются несовместимые алиасы типов / тесты / системы контроля версий» тяжеловато.
Концепция типов фундаментальна и, в общем то, довольно проста - разные данные хранятся по разному, арифметические операции нельзя осуществлять с почтовыми адресами.
Как в эту простую концепцию вписываются типы питона (которые аннотации) или тайпскрипта?
типы питона (которые аннотации)
Аннотации - не типы.
Чего только не придумают лишь бы не читать документацию ;)
Чего только не придумают лишь бы не читать документацию ;)
Да уж, действительно.. Откройте PEP 484, посмотрите как он называется и что там написано
It should also be emphasized that Python will remain a dynamically typed language, and the authors have no desire to ever make type hints mandatory, even by convention.
Правильно?
Собственно так же фундаментально.
У питона как бы есть типы, в этом можно убедиться, забыв распарсить строковую "1" в 1 и попытавшись их сложить.
Просто типов нет у переменных, переменные тут просто идентификаторы.
Типы прикрутили довольно поздно, они не обязательны и тонны кода написаны без них.
Но да, для того и прикрутили.
В сухом остатке динамическая типизация дает маленькую простоту и удобство в замен повышенного шанса потенциальных рантайм ошибок.
Но речь тут не про это, а про важность понимания типов для обучения.
Python тут не страшное зло, страшное зло тут JS с феерическими и неочевидными правилами преобразований, стимулирующими магическое мышление в такой строгой дисциплине, как программирование.
У питона как бы есть типы, в этом можно убедиться, забыв распарсить строковую "1" в 1 и попытавшись их сложить.
Просто типов нет у переменных, переменные тут просто идентификаторы.
Вы говорите о динамических типах питона (которые было бы правильнее называть рантайм тегами, но не суть). Я говорю о тех типах, которые добавляются аннотациями и проверяются тайпчереками типа mypy. Там есть типы у переменных:
x: int = 10
x = "abc"
$ mypy src/test.py
src/test.py:2: error: Incompatible types in assignment (expression has type "str", variable has type "int") [assignment]
Found 1 error in 1 file (checked 1 source file)
Более того, там есть не только численные или строковые типы, но ещё и literal types (типы литералов?). Следующий пример тоже не пройдёт проверку типов, хотя очевидно, что в памяти строки "abc" и "def" представляются одной и той же структурой.
from typing import Literal
x: Literal["abc"] = "abc"
x = "def"
$ mypy src/test.py
src/test.py:4: error: Incompatible types in assignment (expression has type "Literal['def']", variable has type "Literal['abc']") [assignment]
Found 1 error in 1 file (checked 1 source file)
Короче, вы привязываете семантику языка к деталям реализации, а это две разные вещи. Данные одного типа могут храниться по-разному, данные разных типов могут храниться одинаково.
Но речь тут не про это, а про важность понимания типов для обучения.
Я, как человек начинавший с питона, не понимаю откуда вы берёте тезисы про важность типов для обучения. Человек никогда не видевший call/cc, метапрограммирование или макросы будет испытывать не меньшие трудности при их освоении, но из этого не следует, что их нужно давать новичкам.
Python тут не страшное зло, страшное зло тут JS с феерическими и неочевидными правилами преобразований, стимулирующими магическое мышление в такой строгой дисциплине, как программирование.
Чем преобразования джаваскрипта хуже, например, (не менее очевидных, имхо) undefined behavior или правил strict aliasing в си?
вы еще и преподаватель?!?
теперь понятно почему даже толковые люди после всяких "курсов вкатунов" могут нести откровенную ересь на собеседовании..
Я бы объяснил проще. Компьютер - тупой. Он не понимает, что 5 это число, а Вася это имя, ему нужно явно сказать: вот эта ячейка в памяти - для чисел, а эта - для текста. Статическая типизация просто способ донести эту информацию до компьютера
Спасибо за поддержку!
Да, "высота" порога входа также определяет, куда с неё можно "опуститься" :)
Как человек, который начал своё знакомство с программированием с JS могу подтвердить, что после него другие языки поддаются изучению, но кажется несколько сложнее, хотя паскаль, си в школе и универе учил, тут скорее всего всё дело в привычке
Хоть я и люблю python, но соглашусь с вами - начинать нужно с более "строгого" языка. JS же, с его сложными парадигмами, вообще уровень магистратуры, на мой взгляд. Но понятно почему выбирают именно их - легко показать какой то осмысленный "production ready" результат
На первом курсе им давали питон и js , после чего некоторые не могут никак понять, на кой в коде всякие int и bool, как работает обычный for
Плохому танцору учителю и питон мешает.Хотя, раз некоторые не понимают, есть и те что понимают? Может не питоне дело?
Фраза "не могут понять" вызывает некоторое недоверие. Как тогда люди, которые начинали в 90-е с бейсика (того, у которого строки нумерованы), без проблем переходили на С?
Вот это самая мякоть - проблема в том что Питон многое прячет под капот, в итоге студент привыкает к магии и потом впадает в ступор, когда сталкивается с языком, где нужно думать о типах и структурах данных)
Забавно, но я свой путь как программиста начинал сначала с QBasic - всё понятно, что ничего непонятно, а потом стал экспериментировать с html/JS. В профильном заведении там уже конечно паскаль-делфи был, а потом и "Си++" пытались давать.
почему они не могут сделать int a = console.readline()
Ну, это какие-то уж совсем нерадивые ученики должны быть. В питонячке же с молодых ногтей учат: a = int(input()) .
Функция boolean.toint в Паскале называется ord.
А так вообще важность перечисленных свойств для изучения языка программирования является вашим оценочным суждением. Наиболее известный язык, специально предназначенный для обучения детей программированию, Лого (с которого начинал и я) имеет интерпретатор, динамическую типизацию и отсутствие описаний переменных.
Кстати, в Лого есть одна очень важная в методическом отношении фишка – при обращении к переменной всегда указывается, идёт ли речь об имени или о значении. Нет ставящих в тупик
x = x + 1(особенно когда в левой части присваивания тоже выражение), а есть
сделай "x :x + 1где "x означает имя х, а :x означает значение x.
Конечно, в коммерческом программировании заколебёшься каждый раз так писать, но для обучения это очень хорошо.
Интересное наблюдение про `сделай "x :x + 1`. Мне не бы в голову не пришло, что эта особенность синтаксиса может кем-то восприниматься как полезный методический инструмент.
Если не секрет, расскажите про свой опыт преподавания программирования, пожалуйста. Какой возраст обучаемых, направленность, какие-то подробности?
Я по основной работе занимаюсь коммерческим программированием, но иногда работаю с обучением студентов программистских специальностей. Также у меня был опыт руководства курсами повышения квалификации для преподавателей IT дисциплин в вузе и колледже.
Интересное наблюдение про
сделай "x :x + 1. Мне не бы в голову не пришло, что эта особенность синтаксиса может кем-то восприниматься как полезный методический инструмент.
Просто огромное количество людей, изучающих программирование, либо прямо путает имя переменной с её значением, либо не может чётко объяснить соотношение между ними. Что там говорить, если даже в одном и том же стандарте ISO С++, написанном вроде бы профессионалами, связь имени со значением объясняется два раза по-разному.
А в Лого, к слову, вот так вот можно сделать:

Так как взрослых людей уже поздно учить Лого, я им показываю форму set в Common Lisp, в которой вычисляются обе стороны присваивания, и объясняю отличие от setq.
либо прямо путает имя переменной с её значением
А эти люди путают банку с надписью СОЛЬ с её содержимым?
Эта аналогия работает только до определённой степени.
Если у вас функция вызывается рекурсивно 10 раз, её локальная переменная одна или их 10? А если два имени ссылаются на одну ячейку памяти? А может ли быть переменная без имени?
Если у вас функция вызывается рекурсивно 10 раз, её локальная переменная одна или их 10?
10, если нет передачи указателей/ссылок.
А если два имени ссылаются на одну ячейку памяти?
Два указателя ссылаются на один сегмент памяти. Вроде, обычная вещь.
А может ли быть переменная без имени?
А это называется утечка памяти.
Надеюсь, тест прошёл)
Вообще, всегда думал, что отсутствие явного использования ссылок и указателей идёт рука об руку с отсутствием явной типизации (прескорбно, но второе не гарантирует первого), а тут такое исключение из правил. Будем знать.
А это называется утечка памяти.
Анонимные функции/IIFE с Вами не согласятся
Интересно, каким же образом они со мной не согласятся?
Во-первых, речь шла о переменных, а не о функциях, у функций отличается цикл жизни.
Во-вторых, Функции анонимными называются, потому что при их объявлении им не присваивается имя в явном виде, а чтобы их вызвать - нужно знать область памяти, в которой они располагаются... то есть знать их имя.
Они либо вызываются сразу (автоматика сама всё сделает за Вас и, по сути, это не отличается от помещения части кода во вложенные {}), либо для позднего использования вручную именовать их, присваивая их адреса в памяти к ссылочным переменным.
IIFE - это как раз первый случай, где именование функции происходит автоматически движком JS с последующим исполнением на месте.
В языках с сборщиком мусора в рантайме вообще ничего неименованного нет, иначе сборщик мусора не смог бы исполнять свою работу.
То что Лого специально предназначен для обучению программированию, совершенно не значит, что он для этой цели лучше Паскаля. Я тоже начинал с Лого, и могу сказать свое ИМХО - это хорошая штука для преодоления "языкового барьера" перед написанием кода, но не очерь хороший инструмент для обучения программированию.
А что вам не нравится в Лого по сравнению с Паскалем в качестве инструмента обучения?
Очень много что не нравится.
Во-первых, в Лого нет в явном виде многих сущностей и концепций, которые необходимы для обучения основам. Даже банальная типизация там крайне ограничена. Как вот, например, учить на Лого работе с нецелочисленными типами? А ведь это база, нет, базища! Про работу с памятью или вводом-выводом я вообще молчу. С последним вообще беда - он создает не просто упрощенное, но сильно искаженное восприятие того, как программа взаимодействует с этой подсистемой.
Во-вторых, зачем в учебном интерпретируемом языке динамическая типизация? Чтоб обучающимся жизнь медом не казалась? Динамическая типизация - это плохой выбор для учебных целей.
В-третьих, среда. Дельфи все-таки был довольно "взрослой" для своего времени средой, и формировал у человека приближенные к реальным привычки и восприятие. Лого же, по крайней мере в штатных средах, такого восприятия не вырабатывает. После Лого человек во взрослой среде разработки оказывается примерно столь же беспомощным, как и человек, до этого писавший псевдокод на листочке. То есть, он понимает (в рамках скромных возможностей Лого) синтаксис и логику, но совершенно не владет инструментарием разработки
А что не так с нецелочисленными типами? В той версии Лого, которой я учился, были все основные лисповские типы данных.
Работа с памятью в Лого прекрасна - сборщик мусора, который позволяет не заостряться на второстепенных вещах. Совершенно непонятно, зачем учить управлению памятью человека, не являющегося профессиональным программистом.
Касательно динамической типизации я считаю, что это хорошая вещь в большинстве случаев, и во всяком случае для обучения подходит в самый раз.
Что касается среды, то это язык для детей, конечно. Он не имеет промышленной оболочки. Но зато это интерпретатор, где можно непосредственно проверять каждую функцию. Плюс черепаха, визуализирующая результаты.
А что не так с нецелочисленными типами? В той версии Лого, которой я учился, были все основные лисповские типы данных.
Решил освежить воспоминания. Найти мануал по лого с типизацией оказалось не так уж просто. В общем, согласно мануалу, у них из численных типов на всё про всё есть только double. И это отвратительно с точки зрения преподавания. Потому что ученик не сможет ощутить на собственным опыте, что такое разные численные форматы, зачем они нужны, как работают и каковы их ограничения.
Совершенно непонятно, зачем учить управлению памятью человека, не являющегося профессиональным программистом.
Вот это как раз самая-самая база, и этому надо учить всех. Фактически, программа почти всегда (а в некоторых ос по факту всегда) работает именно с памятью. ИМХО не понимая как работает память - не понять как работает программа. Да, не всем надо давать такой объем знаний, какой нужен профессионалу, я даже не говорю сейчас про управление. Но хотя бы понимание того, как именно твоя программа работает с памятью, должно быть.
Плюс черепаха, визуализирующая результаты.
Черепаха, мягко говоря, не самый лучший и не самый репрезентативный интерфейс вывода. С помощью черепахи, наверное, даже можно извратиться и продемонстрировать, скажем, эффект двойной буферизацим, но это будут лютейшие костыли. А главное непонятно зачем всё это.
Из вашей полемики я делаю вывод, мы получаем лесенку, где, как только ты освоил Лого, прыгаем на паскаль, далее трамплином окунаемся в С ветку, если тяготеешь к низкоуровневому программированию, или в С++ ветку, если тяготеешь к высокоуровневым аппликациям.
И не надо на них заострять внимание. (В современных реалиях) Методологически — Лого и Паскаль совершенны для изучения основ программирования. Выпускник такого рода легко на стажировке освоит С, плюсы и так далеее
Теперь этот спор не имеет смысла, по крайней мере на территории России. Потому что (очередной раз) сделан 100%-кирилический язык программирования, а точнее, полностью русифицированный вариант JavaScript.
https://www.cnews.ru/news/top/2025-10-30_bolshe_nikakoj_latinitsy
Преподаватели программирования, настал ваш звёздный час!
/s
P.S. Уже вижу, как во всех учебных заведениях обзывают ставить МАХ и проводить все обучение на скрепном ЯП.
Забавно, да.
Среди кириллических языков программирования у меня есть фаворит https://github.com/tsoding/good_training_language
Типичное импортозамещение - продукт с переклееннм шильдиком (js с переведенными ключевыми словами), некачественный (js взят за основу - отличный выбор), дорогой (нет инфраструктуры, материалов, библиотеки компонентов) и в конечном итоге никому не нужный при наличии оригинала
Люди, объясните, за что минусуете? С чем не согласны?
Вот только использовать PascalABC.NET это так себе идея. Стильно, модно, молодёжно и вот это вот все. Free Pascal выглядит как более традиционный и предпочтительный вариант.
В принципе, всё логично и справедливо. Я когда-то писал в комментариях подобные аргументы, только у меня там ещё был пункт, что неплохо языку иметь концепцию указателя - чтобы формировать понимание, как работает память и что вся современная магия не бесплатна.
Но всё это с одной важной оговоркой: нужно различать совсем начальное обучение и уже вход в профессию.
Первое - это у детей (самое первое знакомство, когда ученики буквально не знают, что такое переменная или условие) и гуманитариев (для общего развития; например, я знаю, что во ВШЭ филологам дают базовый питон применительно к обработке текстов). Второе - профильные классы в старшей школе и студенты, которые с большой вероятностью станут профессионалами. Это два очень разных случая. Первым Python отлично подходит, и часто им же можно и ограничиться. Вторым - да, стоит начать с Pascal, Go, C.
Так в Паскале вполне себе есть указатели.
Их нет в списке критериев автора статьи.
Действительно нет, я про указатели не вспомнил, спасибо за дополнение.
Концепция важная, хорошо, когда её можно показать, не изучая для этого новый язык программирования.
Но ещё хорошо, чтобы можно было бы без них и обойтись как можно дольше (как в Pascal и есть). Уж больно дорого они даются (и не только в плане обучения).
Начинать надо с C++, потому что это не только богатый возможностями статически типизированный язык, но и хорошая тренировка мозгов. После C++ остальные языки покажутся лёгкой прогулкой. Настоящий программист должен точно знать, сколько байт памяти выделяет его код, в какие машинные инструкции он преобразуется, уметь писать собственные аллокаторы, контейнеры и т.д.
А уметь использовать готовые либы в питоне и называть себя программистом - извините, это уровень ПТУ.
Ага. Тоже начинали с C++ - Пол Дейтл, Харви Дейтл. Помню самое сложное было - понять работу указателей... Но у нас был супер препод и он умел объяснять...
В качестве домашних заданий было - реализовать самим функции стандартной библиотеки, такие как: strlen, strtok итд. Ну а потом тонна всевозможных сортировок итд, бинарные деревья, из обход итд.
И все это на первом ,втором курсе для людей, которые первый раз сели за комп на первом курсе. Вот где мозги то кипели))
Указатели наверно год не мог понять! Но тогда и изучал C вобщем-то лишь теоритически.
понять работу указателей...
Что характерно, в питоне их тоже надо понимать.
Как там работать с указателями? Скажем мне надо сдвинуться в массиве на n байт от начала
В питоне для массивов есть слайсы.
a = [1, 2, 3]
b = a
b.append(8)
print(a)
[1, 2, 3, 8]
Такие вот примеры я считаю большой фигой, которую создатели питона скрутили в кармане и с хитрым прищуром тычут обучающимся.
Обычно люди воспринимают переменные как какие-то коробки, в которых лежат какие-то данные. В питоне же оказывается, что это не коробки, а инструкции по тому, как найти коробку (при это коробка может превратиться в ящик на лету).
Ичсх, фига то в документации описана, но интутивно воще неочевидная. Для некоторых типов присваивание работает вот так, а для некоторых иначе. Понять нельзя, нужно запомнить.
Да по большому счёту, работает и работает, запомнить, предположим, не так сложно.
Но если говорить в контексте обучения, то мы ведь не будем искренне ожидать от учеников 8/9/10 класса (когда там программировать в школе начинают?), что они пойдут читать документацию. Я, положа руку на сердце, не уверен, что её учителя/преподаватели читали.
Для некоторых типов присваивание работает вот так, а для некоторых иначе
Оно для всех типов работает одинаково. Другой вопрос, что не у всех типов есть методы, модифицирующие внутреннее состояние, поэтому с некоторыми такого поведения не добиться стандартными способами. Например, для str заменить символ в существующей строке нельзя, можно только создать новое значение и присвоить его:
a = [1, 2, 3]
b = a # b ссылается на то же значение, что и a
c = 'Hello, world!'
d = c # d ссылается на то же значение, что и c
b.append(4) # модифицируем значение, на которое ссылаются и a, и b
print(a) # [1, 2, 3, 4]
print(b) # [1, 2, 3, 4]
d = d.replace('world', 'randomsimplenumber') # создаём новую строку и в d присваиваем ссылку на неё, в c остаётся ссылка какая была
print(c) # Hello, world!
print(d) # Hello, randomsimplenumber!
Понять нельзя, нужно запомнить
Понять переменные в питоне не сложнее, чем указатели в сишке. Там значения существуют отдельно, а переменные могут только ссылаться на них. В том числе несколько переменных на одно значение, как в примере выше
Проблема в том, что для элементарных типов это не так. Хотя логически никакой принципиальной разницы нет.
Но эта проблема касается большинства языков.
Что такое "элементарный тип" для питона? Относится ли к таковым, например, int?
Он иммутабельный с точки зрения самого языка. Но, допустим, если сделать расширение booster, которое реализует функцию incr, принимающую PyLongObject* и меняющую напрямую переданное значение, что выведет следующий код?
import booster
a = 100500
b = a
booster.incr(b)
print(a) # ???
Ответ
Выведет 100501, т.к. в строке b = a идёт присваивание по ссылке. Не важно, какой там тип, присваивание всегда работает одинаково
Сильно упрощённый пример модуля booster (честно, пытался под спойлер засунуть, но судя по предпросмотру, там всё разваливается):
#include <Python.h>
#include "longobject.h"
static PyObject *
booster_incr(PyObject *self, PyObject *arg)
{
PyLongObject *p = (PyLongObject *)arg;
p->long_value.ob_digit[0]++;
Py_RETURN_NONE;
}
static PyMethodDef BoosterMethods[] = {
{"incr", (PyCFunction)booster_incr, METH_O, "Increment a PyLongObject"},
{NULL, NULL, 0, NULL}
};
static struct PyModuleDef boostermodule = {
PyModuleDef_HEAD_INIT,
"booster",
"Module that increments PyLongObject",
-1,
BoosterMethods
};
PyMODINIT_FUNC
PyInit_booster(void)
{
return PyModule_Create(&boostermodule);
}
Например, для str заменить символ в существующей строке нельзя
Бывают типы мутабельные, бывают нет. Бывают строки, присваивание создает копию . Бывают коллекции - присваивание не создает копию,есть для того специальный метод бубен. А вместе с динамической типизацией иногда фиг угадаешь, что должно произойти после оператора =.
Бывают строки, присваивание создает копию
Нет, присваивание всегда задаёт ссылку на значение. В моём примере новую строку создаёт str.replace, а d = только меняет ссылку у d со строки, на которую также смотрит c, на новую созданную
Для людей, начинающих с ассемблера, концепция указателей вообще не представляет не то что труда, но даже интереса.
На С++ надо продолжать. Начинать с него - слишком жестко.
на самом деле можно, если на первом уроке посчитать include и int main за традицию: так надо и всё тут. Мы же будем учить школьников подмножеству c++11, поначалу без классов, без указателей и точно без template. И вот с такими ограничениями единственной сложностью в c++ становится ограниченность int. (В питоне кстати за «так надо» принимается конструкция map(int, input... ).)
Кто-то в 60-е году наверняка считал, что начинать надо с ассемблера. Но в 2025 это уже слишком низкий уровень, чтобы начинать с него. Мы же не начинаем программировать с написания собственного парсера или компилятора.
Ассемблер помогает понять, что в компиляции нет никакой магии.
Может, учить как писать на асме и не надо, но учиться читать асм весьма полезно.
Я конечно не предлагаю всерьёз начинать изучение программирования с Ассемблера, но у меня есть занимательный пример из жизни. Однажды мне ассемблеро-подобный псевдокод (нумерованные строки, команда перехода на конкретную строку) помог объяснить концепцию цикла глухим школьникам. Наверно, жесты над таким текстом получились выразительные.
Когда узнаешь, что компьютер это дурень, который байтики из регистров в память перекладывает и ничего больше не умеет, много других вопросов отпадает.
Сколько памяти занимает экземпляр класса с множественным наследованием? Или любой стандартный контейнер? Что скрывается за оператором +, «настоящее» сложение или operator+(), объявленный неизвестно где и делающий что угодно, вплоть до какого-нибудь приёма данных по сети? Это в обычном С всё видно было, в «полноформатном» С++ как раз таки полно неявностей.
Перегрузку операторов подсвечивает IDE, Ctrl + клик по перегруженному + перенесёт на реализацию, размер структур тоже IDE показывает.
С прост и прекрасен простотой, С++ прекрасен гибкостью с сохранением производительности
Поэтому-то С++ в образовательных целях и хорош. Есть и нижний уровень - указатели, выравнивание и тп. И верхний - вроде неочевидной реализации виртуальности. Для того, кому надо углублённо заняться программированием очень неплохой вариант для как-минимум второго языка. Модет и первого, если не сильно жестить.
Может лучше Паскаль сначала, не большим курсом, чисто академически. Потом в С/С++ вкатываться легче и методологически правильней.
Настоящий программист должен точно знать, сколько байт памяти выделяет его код, в какие машинные инструкции он преобразуется
А плюсы этого больше не дают, всё. Без оптимизаций у вас std::move может быть отдельной функцией (а может и не быть), но без оптимизаций на плюсах на практике никто не пишет (кроме совсем настоящих программистов, пишущих такой код, что глупый оптимизатор его ломает), а с оптимизациями — там такая же магия, как в каком-нибудь JIT-языке.
уметь писать собственные аллокаторы, контейнеры и т.д.
Контейнеры-то легко, и это можно делать на любом языке, а аллокаторы в плюсах — не стоит вскрывать эту тему. Про это на конференциях доклады делают, причём не об алгоритмике и машинных особенностях, а об особенностях языка (типа, как пропагейтить аллокатор std::vector'а в std::string'и, которые там лежат).
И, кстати, почему настоящий программист должен машинные инструкции и аллокаторы? Почему не категориальную семантику его программы и монадические регионы?
По поводу Python и аргументов согласен.
Если у вас сложилось обоснованное, "выстраданное" мнение, как что-то в языке должно быть сделано — скорее всего, в Kotlin это сделано именно так.
Но вот с этим я категорически несогласен. Раньше мне Kotlin очень нравился и казалось что у языка большое будущее. Написал несколько проектов, потом лет на пять забыл. И вот буквально недавно на очередном проекте, судьба опять свела на нем поработать.
Через пару месяцев работы, я посмотрел на Kotlin уже другими глазами, другим опытом и в других условиях. Признаться честно опыт был уже разочаровывающий.
Во-первых. Как бы странно это не звучало, у языка нет внятных причин для существования. Главная идея JB была создать единый язык для решения разноплановых задач: desktop, frontend, mobile, backend. К сожалению, идея не выстрелила и по факту Kotlin нужен только для android разработки. В backend, не удалось как то значимо потеснить Java, более того, Kotlin всецело зависит от JVM и выступает догоняющим по многим ключевым моментом, а то немногое что давало преимущество а именно - корутины, было по факту обесценено с выходом виртуальных потоков. По факту, у языка нет внятного ответа на простой вопрос - зачем он нужен на новом проекте? Быть better-java заменителем, это такой себе аргумент.
Во-вторых. Язык отвратительный с точки зрения дизайна во множестве мест и чересчур переусложнённый. Вы правильно пишете что "В синтаксисе языка явное и заметное предпочтительнее скрытого". Вот только Kotlin пестрит этим тут и там. Для однострочных функций можно не писать тип возвращаемого значение, что находиться за скалярным типов, примитив или ссылка, в Kotlin часто загадка, потому что в отличии от той же Java, в Kotlin такие детали скрывают. Когда мы вызываем функцию над коллекцией, трудно догадаться, она изменит коллекцию или создаст новую. Такими нюансами пронизан весь язык, и если предположим мы можем закрыть глаза на эти проблемы в каком то backend, то для приложений где важна производительность - неявность это геморой, точно также это категорически противопоказано для начинающих. Точно также как куча возможностей сделать одно и тоже.
В-третьих. Непрозрачный interop с Java. Большая часть экосистемы Kotlin - это Java экосистема. Экосистема которая знать не знает и не хочет про фишки вроде null безопасности, про закрытые публичные конструкторы и т.д. А следовательно в безопасном по null языке будет null pointer exception, будет проблемы с сериализацией и прочее прочее прочее, что часто нужно будет обходить костылями и плагинами.
В-четвертых. Непрозрачность. Kotlin - это очень сахарный язык, и практически все в нем реализуется с помощью кодогенерации. Написанная в исходном коде конструкция может иметь совершенно иной вид при генерации байткода. Что само по себе не проблема для опытного, но для начинающего это все сильно усложняет.
Ну нужно начинающему все эти проблемы испытывать. Лучше уж тогда Java или C#. Первая - значительно проще и прозрачнее, второй - сильно сложнее но с огромным количеством плюшек и возможностью писать в дальнейшем вообще практически все что угодно.
Если есть желание учиться сразу и по серьезному то однозначно Си.
Спасибо, что дочитали до этого места!
И за мнение про Котлин конечно тоже спасибо!
Со многим готов согласится, и перебор с сахаром, и сложность, особенно на стыке с Java, всё есть. А как взвешивать плюсы и минусы - это можно по разному, и сильно от области применения зависит. Для меня например "Быть better-java заменителем" - вполне себе аргумент, если он действительно лучше.
А как взвешивать плюсы и минусы - это можно по разному, и сильно от области применения зависит. Для меня например "Быть better-java заменителем" - вполне себе аргумент, если он действительно лучше.
Разумеется. Я скорей имел ввиду - почему Kotlin имеет очень скромный успех на backend в борьбе с Java.
Ключевое слово "если", что на мой вкус, мягко говоря, не так.
Си скорее нет, по той же причине количества неявных допущений.
Тогда уж лучше Паскаль дополнить вводным мини-курсом по ассемблеру или байт-коду.
Если я правильно понимаю, легковесные треды доступны, но потребуют использования примитивов синхронизации. В то время как апи structured concurrency ещё в превью
Вот да, всё обещают. А в Котлине корутины есть давно, и перевести на них проект с Reactor было счастьем.
На мой взгляд, раскраска функций (когда нужно явно размечать, поддерживает ли функция асинхронный работу) в котлине и шарпе - зло во плоти. Подход go/java в этом смысле куда более комфортный, особенно в большой кодовой базе.
На мой взгляд, раскраска функций (когда нужно явно размечать, поддерживает ли функция асинхронный работу) в котлине и шарпе - зло во плоти. Подход go/java в этом смысле куда более комфортный, особенно в большой кодовой базе.
Думаю все-таки не совсем корректно называть что-то злом во плоти, учитывая что в жизни обычно у каждого подхода есть свои плюсы и минусы, а еще есть контекст.
В Go например планировщик зашит в рантайм а все библиотеки спроектированы с учетом этого. В языке все работает асинхронно. Другой вопрос что возможно это мне не нужно. Go выпущен в 2012 году. Также, там где нужно получить данные из одной горутины в другую, вместо лаконичного await появляется куча бойлерплейта с каналами.
А вот для экосистемы Java это уже не родной подход. Более, того не все выполнение асинхронное а только внутри виртуального потока. Вот я подключил библиотеку и я даже не подключаю она вообще поддерживает асинхронное выполнение или нет. Читал в какой-то статье что бывали случаи что в документации отписывались что библиотека работает асинхронно а на деле в блокировке. Более того, вот вызвал я методы библиотеки, а я точно вызвал это все в виртуальном потоке? Или я перепутал и вызвал в обычном и у меня все блокируеться и я об этом и не подозреваю?
В то время как раскрашенные функции вместе с вербозностью добавляют контроль.
Еще нужно учитывать контекст. Раскрашенные функции несколько проще реализовать чем переписывать рантайм. Как результат, async/await изобрели в 2012 году в C#. И подход перекочевал в такие языки как JS, Python, Swift, Rust, Kotlin, Dart. Виртуальные потоки же появились только в 21 версии Java в конце 2023 года и это учитывая что к этому моменту экосистема была так себе готова. Как итог, 11 лет в C# и чуть меньше в других языках был инструмент работы с асинхронностью, в то время Java была в аутсайдерах, писали тысячи проектов где либо нужно было избегать этой проблемы работая с блокирующими вызовами или страдать с реактивщиной, в то время как у конкурентов уже сто лет в обед все работало асинхронно. Дорога ложка к обеду.
Думаю еще предстоит сравнить в опытной эксплуатации на Java все плюсы и минусы подхода. Microsoft к примеру провели свои исследования и признали развитие в сторону виртуальных потоков нецелесообразным. Поживем, увидим.
У меня есть ощущение, что вы не до конца понимаете как работают виртуальные потоки в Java (могу конечно ошибаться).
Не важно что написано в документации библиотеки, виртуальные потоки (stackfull-корутины) работают прозрачно и для вас, и для библиотеки. В любом safe-point может произойти переключение виртуального потока, автор библиотеки (или вы) вообще ничего не должны для этого специально делать.
Да, разумеется, сделать поддержку stackfull корутин намного сложнее, чем stackless. Но мы же не о сложностях реализации? И не про 2012й год. Речь всё-таки про пользователя, и пользователя сегодня. Кстати говоря, первая реализация была сделана быстро (и дубово), и длительность внесения в язык связана во многом с тем (пусть и не только), чтобы избавить пользователя от оверхеда, насколько возможно в подавляющем большинстве сценариев.
Не важно что написано в документации библиотеки, виртуальные потоки (stackfull-корутины) работают прозрачно и для вас, и для библиотеки. В любом safe-point может произойти переключение виртуального потока, автор библиотеки (или вы) вообще ничего не должны для этого специально делать.
Ну во-первых. Будут блокироваться вызовы или нет, зависит от контекста. Вот находитесь Вы в произвольном месте кода и знать не знаете как этот код будет работать, потому как это целиком и полностью зависит от вызывающего - изволил он запустить метод, который запустил метод, который запустил метод... из виртуального потока или платформенного. В отличии от Go, где весь рантайм асинхронный или C# где четко видно по функции синхронная она или нет, в Java смотря на код вообще невозможно сделать никаких предположений о том как он выполниться. Тоже и с ошибками, если кто-то ,на верхнем уровне, создаст случайно не виртуальный поток, то все начнет работать не виртуально и никто этого вообще не заметит.
Во-вторых. То что написано в документации и самое главное, как реализована библиотека - критически важно. Чуда не случиться. Если Вы вызываете библиотеку внутри которой создаются платформенные потоки по старой доброй памяти, или она использует свой пулл не виртуальных потоков или например внутри нее нативные вызовы, которые будут блокировать Ваши потоки, то работа с асинхронностью превратиться в тыкву. Самое неприятное что проблемы могут быть даже не у самой библиотеки а у библиотек которых она использует или библиотек библиотек. Причем самое обидное все это будет неявно. Вообще нет четкой границы, где версия n блокирующая а версия m неблокирующая, можно только или верить документации, которая может врать или путешествовать по кишкам библиотеки и всех ее зависимостей. В отличии от тех же раскрашенных функций, где автор явно выражает это в API.
Да, разумеется, сделать поддержку stackfull корутин намного сложнее, чем stackless. Но мы же не о сложностях реализации? И не про 2012й год. Речь всё-таки про пользователя, и пользователя сегодня.
Ну Вы написали что раскраска функций - зло во плоти, а я считаю что пилить фичу 11 лет, заставляя либо тысячи проектов быть отсталыми и не эффективными или разработчиков подвергать мукам работы с реактивным программированием, только ради того чтобы быть похожими на недо-Go 2012 года - вот что настоящее зло. Есть хорошая фраза - "лучшее враг хорошего". B Java может себе позволять такие фортели только из-за своей мега популярности и огромной значимости для энтерпрайза .
в Java смотря на код вообще невозможно сделать никаких предположений о том как он выполниться
Вы делаете эти предположения на уровне конфигурации.
Если Вы вызываете библиотеку внутри которой создаются платформенные потоки по старой доброй памяти
То у вас уже большие проблемы, и да, автоматически их виртуальные потоки не починят. К счастью, таких библиотек исчезающе мало. Почти всё, что вы можете встретить в продакшене, позволяет конфигурировать способ создания потоков.
Самое неприятное что проблемы могут быть даже не у самой библиотеки а у библиотек которых она использует
Верно, это действительно проблема. Такая же, как во всех языках, кроме, пожалуй, Go, и то я не на 100% уверен. То что у вас снаружи написано async не значит, что внутри нет большого синхронного куска, не позволяющего переключать контекст.
или путешествовать по кишкам библиотеки и всех ее зависимостей
Или проверить треды любым observability-tool в рантайме. В принципе можно даже перехватывать любое создание ОС-треда без большого труда. Конечно, было бы классно знать заранее, но тут вы правы, это невозможно, но и в других языках (возможно кроме Go) это будет больше эвристика, чем реальность.
Ну Вы написали что раскраска функций - зло во плоти, а я считаю что пилить фичу 11 лет
Я вообще не рассуждаю о том, что лучше - иметь очень так себе имплементацию сразу или пилить хорошую 11 лет. Я рассуждаю на состояние сегодня, что лучше - заставлять красить методы (и перекрашивать, что самое плохое) или иметь stackfull на стороне рантайма. И на мой вкус, раскраска проигрывает колоссальным образом.
Вы делаете эти предположения на уровне конфигурации.
Нет. На уровне кода. В любом месте можно задать контекст выполнения.
То у вас уже большие проблемы, и да, автоматически их виртуальные потоки не починят. К счастью, таких библиотек исчезающе мало.
Всю 30 летнюю экосистему Java взяли и по быстрому переписали? Оптимистично.
То что у вас снаружи написано async не значит, что внутри нет большого синхронного куска, не позволяющего переключать контекст.
Есть разница между тем что автор библиотеки написал async но не реализовал, потому что он дурак и тем когда автор ничего не писал и не гарантировал.
Я вообще не рассуждаю о том, что лучше - иметь очень так себе имплементацию сразу или пилить хорошую 11 лет. Я рассуждаю на состояние сегодня, что лучше - заставлять красить методы (и перекрашивать, что самое плохое) или иметь stackfull на стороне рантайма. И на мой вкус, раскраска проигрывает колоссальным образом.
Так Вы и рассуждайте сегодня. А сегодня есть go и java а подавляющее большинство остальных языков раскрашивают функции. Что вы предлагаете, переделать им на виртуальные потоки все? Если нет, то что по Вашему "зло во плоти" то, инструмент который позволил сэкономить 11 лет? Понимаете, если бы Java сейчас выкатила что-то невероятное, инновационное, меняющее подходы кардинальным образом то это еще ладно, но по факту но они просто догнали конкурентов. Поэтому я не понимаю идею про "зло во плоти", есть работающий много лет инструмент а есть может быть чуть более удобное решение(время покажет) которое запоздало на десяток лет. Async/await явно прорывное для своего времени решение которое позволило многим языкам и экосистемам работать удобно и эффективно, в то время как другие десять лет изобретали, так что я бы не стал это называть "зло во плоти" точно.
Нет. На уровне кода. В любом месте можно задать контекст выполнения.
Можно-то можно, но если это происходит, то у вас уже давно всё не работает (или продолжит отлично работать). Идея что stackfull, что stackless корутин в том, что ОС-поток - это дорого. Поэтому если у вас библиотека раньше внутри создавала (зачем-то) ОС-потоки руками - она просто продолжит работать как раньше, а раз вам раньше было с ней ок, то и сейчас будет.
Всю 30 летнюю экосистему Java взяли и по быстрому переписали? Оптимистично.
За 30-летнюю историю экосистемы Java все более или менее распространённые библиотеки и фреймворки уже давно позволяют конфигурировать свои тред-пулы, иначе это уже неюзабельно на тех нагрузках, на которых имеет смысл говорить о виртуальных потоках. А конфигурация виртуальных потоках как раз происходит на стороне тред-пулов.
Есть разница между тем что автор библиотеки написал async но не реализовал, потому что он дурак и тем когда автор ничего не писал и не гарантировал.
Именно, если автор ничего не писал и не гарантировал, то у него не будет под капотом своих тредов. Иначе автор таки написал и нагарантировал. И, обычно, это будет можно конфигурировать из вне. И даже если вдруг нет, то то, что внутри библиотеки какой-то код по каким-то причинам занимает ОС-потоки не будет особо сказываться на остальном приложении (если их немного, а если много - то это уже неюзабельно, ещё до виртуальных потоков).
Что вы предлагаете, переделать им на виртуальные потоки все?
Я предлагаю понимать это на этапе выбора языка, напомню, это было сказано в разрезе выбора Java vs Kotlin сегодня.
я бы не стал это называть "зло во плоти" точно
Ну мы с вами выбираем разную терминологию. Вы бы не стали, а я бы стал. Не вижу в этом никакой проблемы. Впрочем, конечно же, соглашусь, что раньше это могло бы быть аргументом в пользу условного Kotlin vs Java в некоторых контекстах.
Чем плохо?
Я хочу видеть, возвращает ли функция результат сейчас, или её надо подождать, прям в её типах, и хочу, чтобы компилятор мне говорил, если мои ожидания расходятся с реальностью.
Асинхронность — это просто один из эффектов. Эффекты полезно видеть в типах. Особенно в большой кодовой базе.
А проблема как раз в большой кодовой базе: становится безумно тяжело производить изменения. Если мы где-то захотели что-то сделать асинхронным (в большой существующей кодовой базе), нам нужно протаскивать руками всю асинхронность наверх, в каждой сигнатура каждого метода. Включая те, что вообще не причём.
А так, конечно типы - огромное добро, в этом полностью согласен.
А проблема как раз в большой кодовой базе: становится безумно тяжело производить изменения.
Почему тяжело? Легко же. Компилятор вам сразу показывает, где семантика могла поменяться.
нам нужно протаскивать руками всю асинхронность наверх
Если вызывающая функция требует результаты асинхронной функции, то она тоже становится асинхронной, поэтому всё работает как и должно.
Если же не требует, то, насколько я знаю, даже в мейнстримных языках не обязательно раскрашивать все функции аж до main, можно так или иначе detach'нуться от асинхронности.
Тяжело в значении трудоемкости, банально количественно.
Я может что-то не знаю, но обычно красить приходится долго, упорно и до конца (до места где уже покрашено). Иначе костыли вставляются прям совсем мощные, с блокировкой потока.
Я хочу видеть, возвращает ли функция результат сейчас, или её надо подождать, прям в её типах
Async плохо решает эту задачу. Завершения sleep n или даже foldl' (+) 0 [0..10^8] тоже нужно ждать (последнее с поправкой на ленивость), но в типах, если не брать совсем экзотические системы, это не выражается
Эффекты полезно видеть в типах. Особенно в большой кодовой базе.
Я утверждаю, что не все эффекты одинаково полезны, и излишняя гранулярность усложняет написание кода. Async -- один из таких эффектов
Async плохо решает эту задачу.
Зачем вообще нужна концепция асинхронности? Пусть, скажем, любой сетевой запрос всегда блокирует (с точки зрения вызывающего кода — неважно, зашедулится ли вместо него на реальном процессоре что-то или нет).
Утверждаю, что когда человек раскрашивает листовую функцию в Async, он этим говорит, что эта функция может занять произвольное количество времени, и это достаточно важный и реалистичный случай, чтобы остальной мир про это знал. Следовательно, я хочу, чтобы компилятор до меня это знание донёс.
Да, это менее строго определённый эффект, чем, не знаю, частичность (и Maybe) или множество результатов (и [] или какой-нибудь бектрекинг), но это всё равно эффект.
но в типах, если не брать совсем экзотические системы, это не выражается
А, кстати, жаль. Было бы круто, если бы можно было получать какие-то разумные ограничения сверху на вычислительную сложность.
Или снизу, скажем, чтобы легче было доказывать отсутствие некоторого класса атак, скажем.
Я утверждаю, что не все эффекты одинаково полезны, и излишняя гранулярность усложняет написание кода. Async -- один из таких эффектов
Это повод делать системы типов более выразительными.
Но да, согласен: в некоторых языках раскраска может быть неудобной. Checked exceptions в джаве тоже неудобные, что не отменяет полезность Either.
Зачем вообще нужна концепция асинхронности? Пусть, скажем, любой сетевой запрос всегда блокирует
Я не знаю. Мне кажется, это костыль, который делается ради оптимизации в языках где не осилили stackful корутины. С точки зрения поведения async + await почти ничем не отличается от spawn + join, но для того, чтобы второе нормально работало (спавнило гринтреды вместо ОСных, переключало контексты и т.п.), нужна поддержка рантайма
когда человек раскрашивает листовую функцию в Async, он этим говорит, что эта функция может занять произвольное количество времени, и это достаточно важный и реалистичный случай, чтобы остальной мир про это знал.
Но ведь он не говорит этим миру ничего нового. При этом требует усилий, например, пройтись по стеку вызовов и там тоже в асинки покрасить. Возможно, есть языки и сценарии, где разделение между async и обычным IO даёт пользователю какую-то информацию, но я пока с таким не сталкивался
Было бы круто, если бы можно было получать какие-то разумные ограничения сверху на вычислительную сложность.
Есть, кстати, Cost-Aware Type Theory. Там, судя по абстракту, что-то такое описывается. Я её, если память не изменяет, где-то около идриса нашёл, но пока не читал.
Что вы имеете ввиду под "потребуют примитивов синхронизации"? Виртуальные треды с точки зрения пользователя работают прозрачным образом, т.е. "просто работают". Разумеется, если вы модифицируете разделяемые данные, вам всё ещё нужно следить за корректностью с точки зрения модели памяти, что будет верным для любого языка.
Я и согласен фундаментально, и не согласен в детялях.
Я тоже считаю что /pascal отличный для обучения с фундаментальной точки зрения, но мы решаем и множество задач при обучении. Часть из них обусловлена областями применения и практической ценностью, и, к сожалению, паскаль может быть не самым лучшим выбором здесь - да, он живет, но какая это жизнь.
С этой точки зрения python может быть очень хорошим выбором - богатая инфраструктура, несколько областей для задач.
С точки зрения пользы для студента возможно оптимальный выбор, это C# / Java / Kotlin - ЯП общего назначения, универсальные (десктоп и сервера для всех трех, игры на Unity для c#, нативные android приложения для Java / Kotlin).
Но в целом согласен, мне паскаль и делфи очень нравились, мне кажется это одни из самых далеко прыгнувших языков из старой школы (c/c++) в сторону современного практичного мейнстрима (питон/go/c#/Java/Kotlin). С++ конечно современный тоже есть, но это нагромождение легаси и костылей - не то что нужно использовать для обучения
Pascal (Object Pascal) - кроссплатформенный язык, на котором пишутся и мобильные приложения и бэкенд решения, не говоря про десктоп. Можно писать и фронтенд (pas2js). Писать нативные приложения под Андроид/иОС с нативным (FGX) или не нативным UI (FMX).
Да не пишет на нём никто ничего коммерческого, вы же видели количество вакансий в России.
ГрандСмета - Delphi. Altium Designer, Game Maker Studio, СберПро, Ceramic3D, Компас, Keeper. А коммерческого закрытого софта, которых тысячи, никто вам не посчитает.
Лично наша компания предоставляет софт для ПК и планшетов на Андроид крупным торговым компаниям Леруа Мерлен (ЛеманаПро), Петрович, OBI, ...
А также предоставляем бэкенд на Делфи и облачный сервис рендеринга на Делфи.
Я знаю. На самом деле открытый паскаль - один из самых переносимых ЯП. В свежих Делфи большие наборы компонентов для мобилок.
Тем не менее инфраструктура живет, но так себе.
Я люблю делфи, но рекомендовать бы его не стал.
Обучение программированию надо начинать с машинных кодов (ок, пусть будет "ассемблер").
Потом C.
Потом неважно.
Смотря кто и откуда отсеит.
И кого считать программистом.
Когда сами делали РК-86, вообще напрямую писали машинный код в память, и ничего, никого это не отпугивало, ассемблер и отладчик это уже был следующий этап развития. Писали игрушки, обменивались кассетами, было весело. Проблем с пониманием и использованием указателей не было никаких, просто ручками пишешь двух байтовый адрес в ячейки памяти, всё тривиально.
Прям нахлынуло :) Спасибо за приятные воспоминания!
Первой набранной (потоком, без права на ошибку) в машинных кодах программой у меня был HEX-редактор. С его помощью можно было в следующих программах (тоже в маш.кодах конечно) вернуться и исправить ошибку, а не перенабирать всё с начала.
Есть некоторая разница - собрать из спичек игрушечный домик или собрать из них же настоящий дом. ASM соответствовал масштабу тех задач. Всё содержимое памяти РК-86 помещалось на распечатке в несколько листов А4, а большинство программ так и вовсе на одном листе. Сейчас же задачи требуют на несколько порядков большего объема машинного кода.
(ок, пусть будет "ассемблер").
Ассемблер лишний - машинные коды PDP-11 :)
Так как в настоящий момент приходится работать преподом, данная дискуссия затронула "больную мозоль". Меня учили и я учил, что классика это всегда хорошо, поэтому pascal, c/c++ это тот фундамент на котором держится программирование. Но реалии текущей жизни все ломает. В классических языках, ученик хорошо научится тому что такое данные, структуры, виды циклов и прочее (например цикла "До" в python просто нет). Еще раз НО, так как работаю со школьниками которых надо подготовить для сдачи ЕГЭ, то понимаю что можно написать экзамен и на pascal НО на python это сделать проще. Те кто составляет задания хотят они этого или нет "затачивают" его под python. Поэтому что бы я не любил но приходится делать то что надо, учить python.
Спасибо за отзыв, сочувствую!
Отдельно обидно, что в разрешенных на ЕГЭ языках (С#, C++, Pascal, Java, Python) нет Котлина.
А в чем это "затачивание под Питон" выражается?
А у вас молоко убежало...
procedure bubble(a: array of Integer);
begin
var n := Length(a);
var i := 0;Тут что-то не так?
Озарения из прошлого, когда паскаль использовал: помню, что объявления переменных шли всегда вначале, отдельным блоком. Сейчас, наверно, уже можно смешивать в си-подобном стиле.
Это фича PaskalABC
В старых паскалях и реализациях делфи нужно объявлять переменные в блоке перед функцией.
Это PascalABC, там так можно в классическом, отдельным блоком Var
Так точно можно в PascalABC.NET 3.11, где это и писалось. Наверно, право этих строк быть в блоке исполняемых операторов от того, что это ещё и вычисление начальных значений переменных (совмещённое с объявлением, да). Ещё тут может удивлять отсутствие яного указания типа -- так можно, если тип однозначно выводится из присваемого значения.
Современный Object Pascal умеет в инлайн объявление переменных и выведение типов и даже в анонимные функции, итераторы и дженерики
Любят уже у нас на Руси творения Вирта, видимо потому, что тот в советские времена дружил с нами, частенько наведовался в Союз, водил дружбу с Ершовым. По делу, конечно использовать алголо-подобные языки сдля обучения программированию это моветон. Вроде бы уже давно решено, что лучший язык для введения в программирование/cs это Scheme, конкретно великий и ужасный SICP. Остальные языки делают из будущих программистов ментальных калек.
Извините, но весь мир не с вами...
Ну Вы прямо с козырей зашли.
MIT перешел на Python и отменил Scheme/SICP, они признали, что теперь штампуют кадры для рынка. Фундаментальные знания в большинстве случаев не нужны, и даже вредны, будешь задавать много вопросов неуместных, вместо того чтобы грести веслами.
Честно говоря, люблю Python и терпеть не могу Pascal, однако с выводом в основном согласен. Python хорошо использовать, имея прививку от раздолбайства в виде языков с обязательной статической типизацией (к слову, я использую типизацию с проверками и в Python, благо теперь 90% случаев она покрывает).
Меня немного позабавил, правда, пассаж про нелюбовь к отступам. Лично я их очень люблю за то, что в типичном блоке на строку меньше, чем в случае со скобками или begin/end, но это дело вкуса и не может быть ни преимуществом, ни недостатком в первом языке.
Не считаю, что Python как первый язык — прямо катастрофа, но всё же для первого опыта он слишком мало требует от пишущего, вырабатывая у новичка слишком раздолбайский стиль. Наверное, это лечится, но, когда я начинал программировать, Python не было в помине, и я рад, что моим первым языком 40 лет назад был C (потом Фортран и ассемблер 8080, дальше понеслась...).
У нас в школе с 5 класса учат Scratch. И мне нравится
Лучший язык для обучения - Scheme .
Scratch–Logo–Scheme – это прямо немеркнущая классика.

Прочитал заголовок и подумал: неужете Сторялов зарегистрировался на habr.
Показалось.
Статическая типизация не имеет прямого отношения к компиляции. Это всего лишь один из многих способов статического анализа (проверки) исходного кода.
Статический код анализ не сводится к одним лишь к проверкам типов. Сюда так же входит код стайл (нейминг, форматирование и т.п), ограничения по зависимостям между модулями (clean architecture, например), секьюрити проверки SAST, композиционный анализ SCA и т.д. Подсветка синтаксиса и ошибок в IDE (в том числе связаных с типами, но не ограничиваясь ими), в конце-концов, это все тоже элементы статического код анализа.
В ситуации, когда проверка типов прибита гвоздями к компиляции, реализовать такое без ущерба для UX в плане производительности может быть довольно нетривильной задачей (в том числе и для мейтейнеров PABS, насколько мне известно).
В последнем абзаце не понял, как проверки в компиляторе мешают разработчикам IDE (речь же об этом была)? Ну и главная интрига - что означает "PABS"?
PABS это PascalABC на сленге в официальных каналах telegram разработчиков языка.
Подсветка синтаксиса и проверка ошибок в IDE, на минималках, требуют реализовать токенайзер, парсер и тайпчекер. Но делать сборку "объектника" (или 'экзешника", в зависимости от дизайна), чем обычно заниматся компилятор, после ввода каждого очередного символа в редакторе, согласитесь, это как бы против здравого смысла.
Получается, что в некоторых случаях проверка типов должна работать не зависимо от процессов сборки. Поэтому выдавать за благо тайпчекинг, прибитый гвоздями к компилятору, ну такое.
В Python или TypeScript тайпчекинг сделан отдельными проектами (pyright, mypy и т.п.), и я считаю это нормально. Такой подход позволил минимальными усилиями реализовать Langserver, предоставив разработчикам быструю обратную связь в практически любой современной IDE. У PABS, насколько мне известно, здесь были большие проблемы именно из-за выбранной изначально архитектуры.
Понял, спасибо!
Я думаю, в компиляторах тайпчекинг - не самоцель, он там для собственно представления данных изначально появился.
Вообще, у JetBrains как-то получается хорошие IDE делать, несмотря на "встроенную" в компилятор Java типизацию. И да, для этого половину компилятора приходится пере-реализовать, об этом Андрей Бреслав на одной конференции рассказывал.
Кстати, лучшая на мой вкус IDE для Python - тоже от JetBrains.
PABS это PascalABC на сленге в официальных каналах telegram разработчиков языка.
Точно нет - почитайте телеграм канал. PABC скорее
> У PABS, насколько мне известно, здесь были большие проблемы именно из-за выбранной изначально архитектуры.
Нет никаких проблем у PascalABC.NET с этим. TypeChecker вшивается во многие компиляторы, тут нет проблем. И TypeChecker не является частью Language Serverа - в LSP нет понятия типов.
В ситуации, когда проверка типов прибита гвоздями к компиляции
Собственно, компилятор состоит из синтаксического анализатора, кодогенератора и линкера. Это может быть единым, а можно 1ю часть вынести в т.н лангсервер.
Только решительно непонятно, каким боком это и куча специфических аббревиатур относятся к обсуждаемой теме - обучению?
Перечислены какие-то свойства языка, но не объявлена цель обучения. По-моему, первична цель обучения. А под это уже выбирают язык, наиболее эффективно позволяющий достичь заданной цели.
Что касается паскаля, то когда язык зависит от реализации, когда не существует какого-то стандарта языка, то выбор его для обучения кажется сомнительным.
Приведите пожалуйста пару примеров таких целей обучения.
У Паскаля есть стандарт. Есть даже ISO, но для старого Паскаля. Для современного его воплощения - Delphi, есть стандарт и меняется он только от версии к версии, как и в любом другом языке.
Лямбды есть в Паскале? Как там декларативно описывать преобразования данных?
В новой Delphi есть. Но, строго говоря, не сильно они там были нужны, ибо вложенные функции из коробки.
Ну и лямбды с их захватами в обучении студентам мало подходят. Им бы основы усвоить и научиться минимально применять.
Как делать map/reduce вложенными функциями? Мы о разных вещах говорим.
И причём здесь захваты? Учить надо сразу писать промышленный код. А его давно не пишут императивно. Кстати, у меня дочь учат программированию на Питоне. Рассказывает, что они как раз на циклах всё делают. Плохому и на Питоне можно учить.
Там нет лямбд (в Delphi), но есть анонимные функции. Map/reduce делаются через них.
Лучше покажите сразу на примере. Например, есть коллекция { Name, Title, IsAdmin }. Как её превратить в коллекцию { Name } из одних админов? Или любой другой пример, всё равно.
Что показать? Вместо (x -> x.Name) будет
(function(X: rec)
begin
Result := X.Name;
end)Ясно, спасибо. begin и end смотрятся в этом контексте прелестно. А цепочки, наверно, ещё лучше ))
Ну потому что там пока нет лямбд. Пока. Скоро добавится. Сейчас, например, в ЗБТ тестируется nullsafety функционал
И это возвращает нас к первоначальному вопросу: стоит такому учить детей и студентов?
Я думаю, что львиная доля современного промышленного программирования (точно больше половины) — это описание схем преобразования.
Я помню, что лично вы пишете UI на Delphi. Но вы же понимаете, что вы в меньшинстве? А большинство пишет UI на той или иной разновидности DOM. Чаще всего (почти всегда) это HTML DOM. А работа с DOM это цепочки лямбд. Есть, конечно, те, кто вчера пришёл во фронт с Delphi/WinForms, они говорят, мы, мол, будем пользоваться pure DOM API, циклами и переменными. Но статистика говорит сама за себя. Какая самая популярная UI-библиотека в мире? Вот она вся построена вокруг лямбд и цепочек (чейнинга).
Бизнес-логика — опять же, преобразования, в основном. Пришла такая таблица — делаем такую, фильтруем, сортируем, джойним, снова сортируем. Иногда это прямо через СУБД делается, но не запишешь же ВСЮ логику в запросы и хранимки. Остаются, опять же, лямбды. Цепочка лямбд показывает, что надо делать с данными. Как делать настолько редко нужно указать, что в дикой природе почти не встречается. Судя по вашему примеру, вы знаете, что такое LINQ. А «кровавый ынтерпрайз», если он по версии Майкрософта, он именно на LINQ и пишется в первую очередь (даже не на C# как таковом). А что там ещё в бизнес-логике? Вызовы чужого API, который обычно представлен врапперами, и удобен для любого языка, и всё. Ну не алгоритмы же! Это ведь только Степанов думал, что программист на работе пишет алгоритмы. Целый язык под это заточил. (Чужой, причём. Свой бы писал и портил). Все с него и поразбежались, в результате.
Короче, промышленный код без лямбд это сегодня, я бы сказал, какие-то местечковые флуктуации. А детям стоит как можно быстрее рассказывать о декларативности. Лично я своему ребёнку быстро это объяснил, когда увидел, как их в школе циклам учат.
Это очень сильно заблуждение. Зачем мне использовать лямбды и LINQ? Я не обрабатываю исходные данные в коде, если они находятся в БД. Использование запроса на обработку и отбор данных намного эффективнее передачи кучи данных из БД и применение к ним фильтрующих лямбд.
Построение UI не HTML единым ограничивается, он просто навязан, потому что удобнее инструментов просто не нашли для построения HTML. Оттуда он перешёл частично в десктоп и мобильный UI, но далеко не полностью и крайне не эффективен в этом. И также, не удобен в написании с лямбдами или без.
Я через дизайнер создам гибкий интерфейс на порядок быстрее, чем вы кодом DOM структуру. Дизайнер UI в Delphi не стоял на месте все эти годы, а получил массу инструментов для создания гибкого UI.
Я создаю гибкий макет в дизайнере окна, и создаю отдельно представления контролов в отдельном дизайнере. В моем распоряжении макет окна, фреймы, представления контролов, которые могут иметь и не иметь дополнительной внутренней логики.
Вы сейчас ограничены знаниями WinForms и декларативного описания UI, но у меня есть куда более быстрый способ создания UI.
Например, возьмем построение UI для чата, а именно для отображения сообщения, которое может состоять из множества блоков: текст, вложения, реакции и т.д. Я строю через дизайнер макеты этих маленьких блоков и могу визуально оценить то, как они будут выглядеть и работать. Естественно с адаптацией под гибкий интерфейс.
Сообщения пусть берутся из датасета, которые читает данные из локальной БД, при чем он читает их частично в обе стороны по мере необходимости для отображения. Я просто привяжу кол-во сообщений к списку и свяжу набор данных с этим списком. Готово. Останется написать парсер самого сообщения, который будет преобразовывать содержимое сообщения в блоки. При этом, блоки сами содержат код наполнения себя и могут также рекурсивно создавать блоки. Всё это обойдется мне в строк 50-100 в зависимости от кол-ва блоков.
Это тот же самый декларативный подход, только код у меня распределен по модулям, с которыми он связан, а бОльшая часть кода с UI отдана на дизайнер и отсутствует вовсе. При этом, мы не коснулись ещё представлений, которые определяют как элементы будут видеть. Это тоже независимо и механизм схож в CSS, только делается это представление тоже визуально, а не через CSS-код. Набором представлений я могу менять не только визуальный вид элемента, но и то, как и где он будет отображать данные и частично могу влиять на его поведение, анимацию и т.д. (но не положение, положение всегда задается в одном месте).
Это я вкратце описал кроссплатформенный фреймворк FMX, который входит в поставку языка и среды разработки.
Мне не нужны там лямбды, я либо работаю с датасетами, которые могут брать данные откуда угодно (даже в реалтайме с REST сервера) или генерироваться на лету, либо работаю биндингами, которые так же настраиваются визуально и работают в дизайнтайм.
Я где-то уже публиковал видео, в котором я создавал кроссплатформенный онлайн-радио плеер, который работал буквально внутри среды разработки во время разработки. И заняло это минут 10.
Я же написал: если есть смысл, то да, декларации выносят в DSL (SQL). Но вы будете писать каждый редактор (3D-редактор, например) на основе СУБД? Или будете все-все преобразования форматов проводить строго через СУБД? Или вы считаете, что в редакторе нет коллекций, которые надо сортировать, фильтровать и джойнить? Ну так, они там есть. И работа с ними составляет важную часть бизнес-логики. Основную, я бы сказал.
Про WYSIWYG мы в прошлый раз уже говорили. Моя позиция не изменилась: профессионалы им не пользуются, точка Это не снобизм, это вопрос качества UI. Понимаете, я не пишу UI на скорость. Нет у меня такой метрики. И задач таких нет — создать онлайн-радио плеер за 10 минут. Я делаю продвинутый UI и могу целый день добиваться какого-то сложного поведения. Вот пример, хоть и не мой:
Сделайте такое WYSIWYG'ом, а я посмотрю. Я сильно подозреваю, что и вы дописываете сложное поведение кодом. Просто у вас это императивный код, и вы только делаете вид, что обошлись WYSIWYG-редактором. А мне удаётся сохранить очень высокий уровень декларативности, потому, что я изначально пользуюсь инструментами, которые под это заточены. Вот этот пример выше, кстати говоря, решается декларативным и очень понятным кодом.
Во-первых ваш пример - это дизайнерский шаблон, созданный в After Effects или подобном редакторе и по сути не является примером. Во-вторых, да, я легко могу сделать такой интерфейс WYSIWYG'ом. Вплоть до анимаций. Без кода. Код будет только на смену темы со светлой на темную, нужно вызвать смену набора представлений с одного на другой (5 строк кода).
Я такое уже делал:
https://youtu.be/u3dtSJO9aPo
Вдобавок ко всему, у меня здесь на самом деле не стандартное окно с эффектами, а не пред. записанное. Таких макетов как вы скинули сотни на dribble, только приложений таких в реальности нет, потому что мало кто делает нестандартное окно и вся целостность дизайна теряется. У меня - нет.
Вот вам ещё один пример созданный через WYSIWYG
https://youtu.be/uWybphjr2g0
И опять же, это не просто нечто анимированное внутри контейнера (например страницы браузера), а полноценное рабочее приложение работающее на Win/Linux/MacOS. Все элементы в этом окне реальные, а не статичные картинки. Дай им данные и они будут работать.
Мой пример — это пример, взятый с Habr Q&A. (Это такой, типа, СтекОверфлоу, но на русском и с более адекватной публикой). Место, где профессионалы, в том числе разработчики UI, задают вопросы, как им сделать то-то и то-то. Вот я и взял один из тамошних вопросов по UI. Ещё я выбрал этот вопрос, как похожий на типичные задачи, которые мне приходилось решать в профессиональной жизни. Вопросов, как за 10 минут написать радиоплеер я на Habr Q&A что-то не встречал. И мне самому такие задачи тоже никогда не поручали. Потому, что это, извините, хоббиизм. В промышленности НЕТ таких задач: «напиши что-нибудь за 10 минут с функционалом радиоплеера».
С этого я и начал: детей и студентов учить надо не хоббиизму, а тому, с чем в профессиональной жизни придётся столкнуться.
Я такое уже делал:
https://youtu.be/u3dtSJO9aPo
На видео вы выбираете один из готовых эффектов перехода, и ни один из них не соответствует поставленной задаче (я это могу с уверенностью сказать, потому, что постановка очень нестандартная). Что дальше? Дальше вы либо идёте к заказчику/работодателю и говорите: табуретку запилить не могу, могу только буратино (то есть, предлагаете подогнать дизайн под инструмент). Либо вы идёте писать свой эффект перехода. И делаете это императивно. То есть, кодом, но плохим (это примерно, как использовать колбэковый .animate() на джаваскрипте — я бы такой код у программиста просто не принял: его трудно поддерживать и он не имеет автоматической оптимизации и прочих плюшек). Об этом я и говорю. Лучше изначально описывать желаемое поведение декларативным кодом, и иметь над ним полный контроль: когда попросят добавить/убавить кругов, или изменить временнОй характер преобразований, или что-то ещё, что хотят заказчики/работодатели, и чего не предусмотрено в библиотеке готовых переходов.
Вы не понимаете о чем говорите. Первое, пример с радио - это пример того, как можно быстро сделать что-то полезное. И оно будет полностью функциональным. Т.е. будет уже работать как надо столько, сколько нужно. Я так же быстро могу сделать просмотрщик 3D панорамы за те же 10 минут и, что самое главное, такая задача у меня была на работе. У нас два штата разработчиков: Дельфисты и Шарписты. И задача стояла в разработке прототипа просмотрщика панорам. Кто быстрее, тот и будет разрабатывать конечный продукт. Локальный "хакатон" (просто конкурс). И да, теперь именно моя разработка стоит на Андроид-планшетах в таких магазинах как Леруа Мерлен (он же ЛеманаПро).
Второе, каким образом я должен был задним числом показать вам именно тот эффект, который был представлен на вашем шаблоне? Моё видео 2022 года. И это лишь демонстрация смены набора стилей. Предустановленные эффекты там не касаются смены стиля, это общие классы для трансформации текстуры. Я могу любую трансформацию взять из готовых или написать с нуля, потому что это стандартный пиксельный шейдер. Я могу использовать любой шейдер с любым эффектом. У меня нет ограничений, вы их для меня сейчас сами выдумываете. И да будет вам известно, что я даже движок skia, который используется в chromium, могу использовать для отрисовки своего интерфейса (FMX позволяет менять графические бэкенды). И плюсом, могу задействовать 3D контекст в 2D и наоборот, 2D контекст в 3D (т.е. на плоскость внутри 3D могу поместить свой интерфейс с полноценным взаимодействием с ним). А также, могу рендерить 3D контент напрямую на рабочий стол без подложки. Если и этого мало, я могу получить прямой доступ к GPU контексту и делать любые низкоуровневые операции.
Ну так это не я, а вы написали: «Я такое уже делал», и показали видео, где видно, что вы ничего не сделали, а просто взяли готовый эффект и бахнули на форму. И этот эффект поставленной задаче не соответствует. И ни один из эффектов, которые видно на видео, задаче не соответствуют тоже. Вы покажите, как вы будете нужный эффект писать в WYSIWYG-редакторе за 10 минут.
Но теперь, я вижу, вы уже поправились: это, мол, «стандартный пиксельный шейдер». Ну и как вам тогда поможет WYSIWYG-редактор? Для написания пиксельного шейдера? WYSIWYG-редактор поможет только тогда, когда вы чужое применяете. Профессионалы так не делают. И даже не потому, что готовый переход из скудного набора убого смотрится, а потому, что заказчик всегда попросит чего-нибудь поменять, а раз так, то и предлагать готовое смысла нет, всё равно потом переписывать десять раз.
Зато написанный (всё равно текстом) шейдер вы потом подключите через WYSIWYG-редактор. Сказочное удобство.
И причём тогда вообще Паскаль/Делфи? Шейдеры пишут не на нём. Я сразу сказал: нужен другой язык.
Наконец, пиксельный шейдер — в целом неадекватный инструмент для решения этой задачи. По очень многим причинам. Причина раз: вы не можете использовать те же единицы (через переменные), что и в основном интерфейсе. Привязаться к базовому размеру шрифта через rem, просто к размеру шрифта через em, к долям вьюпорта, и т.д. Про адаптивность что-нибудь слышали? Причина два: вы не можете в вашем шейдере использовать значения из основного кода. Тупо, цвет из темы. Вам его придётся гонять туда-сюда через параметры. И всё остальное тоже. Просто взять переменную «цвет темы» с таким подходом у вас не получится. А вот если эффект описывается на том же языке, что и стилизация интерфейса, то такой проблемы не возникает. Причина три: к моменту применения эффекта, если у вас пиксельный шейдер, у вас уже не будет UI как такового. Будет отрастрированная картинка. А если вам понадобится чтобы один контрол был всегда НАД всем, и его переход не затрагивал? Или он динамический и его обновление должно быть видно во время перехода? Причина четыре: код шейдера просто сложнее, чем, скажем, опорные точки радиальных градиентов. Я не напишу этот эффект за 10 минут (это нереально), но я напишу эффект, в котором вы сможете разобраться за 10 минут. А вот написать шейдер, в котором можно разобраться за 10 минут… Это вряд ли.
В общем, у меня вопросов больше нет.
"Я такое делал", потому что это смена темы, а не смена именно с таким конкретным эффектом. Эффекты я могу менять любые. Вы же, не сможете сделать смену темы с трансформацией всего содержимого целиком, типа Wave эффекта.
1. Пиксельный шейдер используется для обновления интерфейса. Для смена одно кадра на другой. При чем я могу применить его отдельно для каждого контрола или целиком на весь интерфейс. Я могу оставить один элемент поверх. Мне для этого делать ничего не надо, это очень просто. Я просто поменяю Z-Order перед сменой кадра.
2. Пиксельный шейдер да, пишется на другом языке, только готовых шаблонов полно. И я могу их применять так же просто, как, например, это применяется в Unity. Я могу выбрать из галереи или написать сам.
3. При чем тут размер шрифта и пиксельный шейдер? Пиксельный шейдер в данном случае имеет минимальный приоритет. Интерфейс рисуется не шейдером, он используется только как вариант смены темы. Единицы измерения у меня в программе измеряются в "попугаях", т.е. не зависят от платформы. Весь интерфейс в целом может быть отскейлен с произвольным значением в любой момент времени.
4. Адаптивный интерфейс? Если бы вы смотрели все видео, которые я демонстрировал, то видели бы клиент ChatGPT, который одинаково выглядит на телефоне и десктопе, но подстраивается под соотношение сторон. При чем, это один и тот же проект, просто собранный для разных платформ. При этом, скейл (DPI) на мобильном телефоне очевидно намного выше, чем на моем экране в FHD. Мне не нужно вообще об этом думать, размер картинки и точность шрифтов будет на всех платформах нужная.
5. Если надо, я могу заняться ерундой и применять градиентные анимации всюду, только зачем? В вашем примере происходит простой "Shape" эффект, который есть и из коробки (в видео не показывается)

И если что, то кнопка и дисплей калькулятора и так не меняются при смене темы.
Это именно вы ограничены тем, что делаете это градиентами, а не я. Я могу применять намного более эффективный способ - шейдеры. Каждый элемент в интерфейсе имеет возможность применять шейдер на себе, так рисуются тени, свечение и т.д. Или целиком на весь кадр. Или часть кадра.
6. Этот "скудный" набор состоит из 20+ транзитных эффектов из коробки и может быть применен к чему угодно, это на 20+ эффектов из коробки больше, чем где либо.
Наконец, пиксельный шейдер — в целом неадекватный инструмент для решения этой задачи. По очень многим причинам. Причина раз: вы не ...
Отсюда начинается откровенна глупость, связанная с не пониманием того, как и что работает.
И да, анимация с ключевыми точками у меня тоже есть из коробки, как для любого числового свойства контрола, так и для цветов, градиентов и т.к. Есть и анимация которая "следует маршруту" Path (это как элемент d в SVG).
Зачем мне использовать лямбды и LINQ? Я не обрабатываю исходные данные в коде, если они находятся в БД. Использование запроса на обработку и отбор данных намного эффективнее передачи кучи данных из БД и применение к ним фильтрующих лямбд.
А ты точно продюсер? (с)
https://learn.microsoft.com/en-us/ef/core/querying/
EF Core passes a representation of the LINQ query to the database provider. Database providers in turn translate it to database-specific query language (for example, SQL for a relational database). Queries are always executed against the database even if the entities returned in the result already exist in the context.
Я знаю о LINQ как о генераторе запроса, но речь шла о LINQ как об обработчике данных. Map, reduce и т.д.
Тогда тем более непонятны претензии к LINQ. Лопатить в рантайме данные из базы можно на любом языке. Этим страдали и похапешники, и жопаскриптеры, и джангисты часто балуются, и MS Access в руках макаки так же работает, и в гошке с веселым ORM через написание чистых SQL в бэктиках так можно, и с LINQ сдуру можно SELECT * FROM table с последующим перебором выхлопа на стороне приложения.
Это потом только статьи пишут - почем лег сервер от автосгенерированных запросов ОРМ =)
Рукожопы, сэр. Впрочем, не только лишь все ORM предоставляют такой функционал, а многие из тех, что предоставляют, делают это максимально неудобным способом, чтобы джангисты не вздумали писать запросы через Query Builder.
Биндинги и REST https://youtu.be/2GHXCmmmS80
ChatGPT клиент https://youtu.be/E-gUItG9330
ChatGPT клиент https://youtu.be/Pxmn2v_PWB0
Мы учим детей как раз лямбдам и LINQ, сочетая их для баланса с алгоритмами - так что всё правильно
Лучше покажите сразу на примере. Например, есть коллекция
{ Name, Title, IsAdmin }. Как её превратить в коллекцию{ Name }из одних админов? Или любой другой пример, всё равно.
// PABC.NET 3.11
type
Person = auto class
Name, Title: string;
IsAdmin: boolean;
end;
begin
var a := [
new Person('Ivanov','Title1',False),
new Person('Sidorov','Title2',False),
new Person('Petrov','Title3',True)
];
var Names: array of string := a.Select(person -> person.Name).ToArray;
Names.Println
end.map-reduce спокойно сделаются через обычные функции, нарисовать можно как удобно.
Или вы реально думаете что std::trаnsfrom обходится без цикла? Надо знать как оно работает. Цикл остаётся циклом, как его ни называй.
Ну вообще-то нет. Работает оно через условные переходы.
В цикле :-) Точнее там сам процесс зациклен, пока итератор способен отдавать значения.
И важно чтобы студенты сами могли это вручную сообразить, чтобы понимали что там под капотом. А то зачастую для них это непонятная магия. Мол циклов больше нет и они устарели. Нет - конечно саму форму такой записи без циклов надо знать и уметь применять. Но и в основах надо разобраться и понимать что стоит за стандартной библиотекой.
Вы себе можете, конечно, представлять семантику этого процесса в виде цикла, но никакого цикла там нет. Есть действия над структурой данных, которые можно представить элементарной операцией, а можно повторяющимися переходами, циклом, рекурсией и бог весть как ещё. Вы с детства познакомились с циклом, как конструкцией структурного программирования, и представляете там его себе, но его там нет ни на каком уровне рассмотрения (разве что, может, какая-то конкретная реализация стандартной библиотеки может быть написана на C/C++, и там в исходном коде будет цикл). С тем же успехом можно себе представлять рекурсию.
Какой-то компилятор в определённых условиях может подставить одну векторную операцию.
Нет, не будет у вас векторной операции. Ни на одном процессоре. Можете мне поверить, как очень хорошо знакомому с VHDL.
Потому что неопределённые условия. У вас на итераторы накладывается слишком мало ограничений для векторной операции.
Всё подобные вещи - это циклы с условиями и никак по-другому их выразить нельзя, просто последовательный перебор итератора. И обучающиеся должны это чётко и правильно воспринимать - как оно работает на этом же самом с++ и как оно в этой библиотеке на этом же самом языке записано. Это всего лишь приятное дополнение. Но это не часть языка, а лишь часть библиотеки.
Возможно, в данном конкретном случае в компиляторе C++, векторизация и не будет выполняться. Но это несущественно вне рамок изучения машинно-зависимой оптимизации, то есть гораздо более глубокого и узкого знания. Я считаю, что обучающимся на первом этапе нужно сосредоточиться на денотационной семантике, то есть на том, что, собственно, они хотят получить. На основных паттернах кодирования в выбранном языке. А уж потом в деталях разбираться, как это происходит.
Всё подобные вещи - это циклы с условиями и никак по-другому их выразить нельзя
Можно выразить через переходы, можно через рекурсию, можно через аппликацию (макроподстановку). Да хоть через какой-нибудь аналоговый регулятор. Я студентам как раз объяснял возможность выражения алгоритма разными способами.
Я согласен, но ИМХО все эти map-reduce вообще к программированию по-крупному и не относятся. Это скорее способы выражения отношений между сущностями и методам их обработки. Т.е. это понятия выше обычного программирования и уже ближе к математике.
А уж чем реализовывать - дело вторичное, циклом на чистом си с указателями на функции или обёрткой на с++ через transform - совершенно не важно. Можно показать оба варианта.
var lam: integer → boolean := x → x > 5;
Arr(1..9).Select(x → x + 1).Where(lam).Print;Лямбды есть в Паскале? Как там декларативно описывать преобразования данных?
Всё есть уже давно
Вроде бы под все ваши доводы подходит golang, при этом он сразу хорошо бьёт пол рукам и прививает надёжный стиль программирования. И он серьёзный.
Я как Android разработчик, который преимущесвенно на Kotlin пишет, категорически не рекомендую начинать изучение программирования с Kotlin. Kotlin слишком... не знаю, как сказать... обобщенный язык, смешение стилей функционального и ООП. К нему лучше более подготовленным подходить.
Pascal - просто идеален для обучения: статические типы, четкое разделение на функции и процедуры, указатели (как в Kotlin объяснять указатели - я понятия не имею).
Потом какой-нибудь ООП. Например, та же Java, где ООП гвоздями приколочено.
Только потом уже Kotlin.
По моему мнению, востребованность в индустрии для первого языка - это не то, на что стоит обращать внимание. Вопрос об обучении программированию в принципе, а не о разработке прикладного ПО.
Только потом уже Kotlin.
А промптинг когда преподавать ? ;)
Не понимаю юмор. Вопрос был об обучении программированию. Я выразил мнение, что к Kotlin следует более подготовленным подходить, если конечно, нужен именно Kotlin.
Пример с "Hello world":
на Pascal writeln - практически системный вызов, функциональщина в чистом виде
на Java System.out.println - ООП прям так и прет, класс-поле-метод
на Kotlin println:
под JVM - обертка над Java и ООП под капотом
Native - практически системный вызов
Объяснить разницу в Kotlin нереально без знания Pascal и Java. В Kotlin слишком много свободы, в процессе обучения лишняя свобода скорее вредна.
Промптниг можно преподавать (хотя зачем его преподавать - я хз) после наработки опыта в программировании. Чтобы человек понимал, что ему нейронка выдает.
Pascal, современный Pascal - в том числе ООП язык. Он может как в функциональщину, так и в ООП. В Паскале ты можешь написать как writeln, так и System.WrIteln, Так и задействовать другой модуль с классом, который предоставляет доступ к I/O.
Помимо этого, он кроссплатформенный и позволяет писать для того же Андроида.
на Pascal writeln - практически системный вызов, функциональщина в чистом виде
Вы путаете функциональщину и процедурщину. Многие, кстати, путают. Пишут на C/C++ функции без классов и глобальные переменные, и говорят: у нас тут чисто функциональное программирование.
Как в том анегдоте " - До или после? - Вместо!"😀
На мой взгляд программист обязательно должен освоить Си. С плюсами вопрос дискуссионный, но чистый Си - надо! Осознание указателей - это особый рубеж, который надо преодолеть, иначе ... неосиляторство) Скорее всего, Си когда-нибудь придется хотя бы читать. Может быть, Pascal имеет смысл использовать для обучения на самом раннем этапе, но очень недолго.
И вообще, нормальному программисту так или иначе придется познакомиться с каким-либо компилируемым языком, языком для виртуальных машин и каким-нибудь интерпретируемым языком. И здесь я бы выбрал триаду C, Java и Python. Си великолепен тем, что дает отличное представление о кроссплатформенной разработке в том числе на низком уровне. Java - это пример очень хорошей инженерной культуры (JSR, интерфейсы, контракты, обратная совместимость). Ну а Python - это шедевр среди интерпретируемых языков. Выразительный и ни на что не похож.
Человек не знающий как устроена машина и неумееющий давать ей команды на родном для неё языке не достоин называться программистом, и подпускать таких к пограммированию категорически нельзя! Начинать программировать надо с создания своей простой вычислительной машины и изучению её машинного кода. И только после этого переходить к языкам, компиляторам и операционным системам. Иными словами, обучение должно в сокращенной форме повторять путь по которому шел прогресс. Так преподают математику и физику, так должно быть и в компьютерных науках!
Я преподавал и много, для себя вывел следующее - лучший язык для понимания - это Си, без плюсов.
Потому как там четкая система типов, указатели (очень важная штука для хорошего программиста), а при левелапе можно и ООП настоящее дать, но уже в плюсах.
То, что в статье - полностью согласен.
Про Python могу очень много плохого наговорить с аргументами, его преподносят часто как "гораздо лучший, чем лапшистый и с кучей магии PHP", а по факту лапши и магии там в разы больше. Я не люблю ни тот, ни тот, но, к сожалению, ввиду того что Python преподается практически во всех университетах мира, он стал стандартом де-факто, увы.
по факту лапши и магии там в разы больше
Можно пример магии, не описанной в документации?
А где я писал, что что-то не описано в документации? )
Ну и описанная магия магией быть не перестает.
Можно пример магии, ...
Магия — это генераторы, итераторы и декораторы.
Да, генератор ещё объяснить просто. Остальное.
Лучше всего Pascal. Никаких шаблонов. Никакой перегрузки функций и операторов. Максимум, что может быть, так это процедурный тип. И всё.
Ну, уж ) генераторы/итераторы и декораторы - это как раз не магия, а хороший синтаксический сахар (за который как раз этот язык можно и нужно любить).
Магия - это не очевидное поведение.
Например, в Python значения "по-умолчанию" у фии, которые не являются примитивом, сохраняются между вызывами этой функции, ну или то, что округление по-умолчанию - "бухгалтерское".
Лапша - например, задекларировано, что все есть объект, но при этом чтобы посчитать кол-во символов в строке нужно сделать "len( строка )" вместо "строка.len" и тд. Т.е. есть собственные базовые фии вызываются иногда "из объекта", а иногда "на объект", всякие магические названия вроде __main или не менее магические названия приавтных членов класса, геттеров/сеттеров, кваргсы и тд - те когда нет четкой и жесткой структуры работы.
магии, ...
Магия — это генераторы, итераторы и декораторы.
Обязательно учить абсолютно весь питон, со всеми его возможностями?
Лучше всего Pascal. Никаких шаблонов. Никакой перегрузки функций и операторов.
Современный Паскаль - это автовывод типа, дженерики, лямбды, перегрузка функций и операторов. И процедурный тип конечно - куда же без него )
// PascalABC.NET 3.11
type
Vec3 = auto class
x, y, z: real;
class function operator+(v1, v2: Vec3): Vec3
:= new Vec3(v1.x + v2.x, v1.y + v2.y, v1.z + v2.z);
class function operator*(v: Vec3; r: real): Vec3
:= new Vec3(v.x * r, v.y * r, v.z * r);
class function operator*(v1, v2: Vec3): real
:= v1.x * v2.x + v1.y * v2.y + v1.z * v2.z;
end;
begin
var v1 := new Vec3(1,2,3);
var v2 := new Vec3(4,5,6);
(v1 *v2).Print;
end.Извращенный синтаксис С - как раз то, что нужно неокрепшим умам.
Достаточно простой синтаксис кмк.
Один только приоритет операций чего стоит.
Не помнишь - ставь скобки.
А что, есть языки без приоритета операций? ;)
Ну вообще-то есть. Например, неоднократно рекомендовавшийся здесь Scheme.
Но в большинстве языков приоритеты операций вполне естественны и не нуждаются в специальном заучивании.
Ну да, не нуждаются ;) В Си просто операторов значительно больше чем в Паскале. При желании можно построить выражение в котором чорт ногу сломит. Ну, не надо так делать.
APL и его потомки, например. Форт. Ребол.
Форт забавное. Стековая машина то самое для неокрепших умов ;)
Разве тут кто-то советовал обучать детей Форту? Форт - для опытных бородатых дядек, которые знают, чего хотят.
Форт – это язык для обучения студентов написанию интерпретатора форта на другом языке :)
Это очень идиосинкратический синтаксис, который его авторы делали под себя - как им было удобно. Вам он кажется простым лишь в силу привычки.
Два равно вместо одного в сравнении - это же готовый капкан. Совершенно не нужная открывающая скобка в блоках. Мутнейшее описание сложных конструкций из массивов, функций и указателей. Это так, сходу.
Если про == я могу согласиться, то что не так с открывающей скобкой в блоке? B про "мутнейшее описание сложных конструкций" можно подробней? - прямо очень интересно, без всякого сарказма.
что не так с открывающей скобкой в блоке?
Она просто не нужна и не выполняет никакой полезной функции. Поэтому так до конца и не определились - куда ее ставить, выравнивать с закрывающей или просто тыкать в предыдущую строчку.
прямо очень интересно, без всякого сарказма.
Вот мы дожили, что обычные вопросы по умолчанию уже считаются саркастическими. Токсичность 80 уровня разлита в воздухе :-( Это я не в ваш адрес, если что.
"мутнейшее описание сложных конструкций
Идея авторов была такой: объявление должно выглядеть так же, как использование. Поэтому указатели объявляются как переменная. но со звездочкой впереди, функции - как функция без названия и т.д.
Идея оказалась очень неудачной. Попробуйте с ходу написать объявление массив указателей на функции, принимающих указатель на массив, или что-нибудь в этом духе.
Паскаль в этом месте гораздо понятнее и удобнее.
Поэтому в новых языках вроде Раста (и даже в проектах переделки синтаксиса С++) отказались от описателей ДО имени переменной и изменили синтаксис в лучшую сторону.
А вообще, по моему личному мнению, лучший синтаксис был в языках CLU и Dylan. Никому не известных, что заставляет задуматься, является ли синтаксис вообще важной вещью.
Ссылка про проекты-перделки кривая. Интересно посмотреть
Все-таки если не лезть в дебри, то оно вполне, ИМХО (а дебри везде есть, это как времена в английском;))
Соглашусь, что в Паскале проще - но есть еще один нюанс, который я учитывал, давая эту рекомендацию - все-таки хорошо учить не мертвому языку, Си в этом плане куда лучше. И есть потом куда развиваться (я про плюсы и дебри).
Попробуйте с ходу написать объявление массив указателей на функции, принимающих указатель на массив, или что-нибудь в этом духе
Когда мне вдруг такого захочется, я буду бить себя линейкой по пальцах ;) Структуры данных лучше все таки сначала спроектировать а потом кодить.
Ну, а в Паскале как такая задача решается? ;)
Потому как там четкая система типов
Integer promotion rules назубок помните? Ученикам рассказываете? Хорошо экзамены по ней сдают?
Говорить, что в си чёткая система типов — это очень смешно.
Всё-таки, выбирая лучший язык для обучения, нужно учитывать цели этого самого обучения. Если учат будущих программистов, то Pascal однозначно лучше, чем Python, но вообще-то стоит подумать про C вместо Паскаля. Если язык программирования учат как дополнительный курс, не с целью стать программистом, просто, как удобный инструмент, то возможно Python будет лучше, потому что он может пригодится практически во многих сферах.
Мне всё-таки кажется, что удел Pascal - это школы, потому что школьники ещё не знают, в какую сторону они пойдут, а этот язык заложит академические основы программирования, при этом сам по себе он в будущем не пригодится.
Имхо, использование полувымершего Паскаля при обучении вместо первого по популярности Питона выглядит как ненужное усложнение и пустая трата времени. Ну, есть Питон, который доказал свою эффективность в последние десятилетия, он задумывался простым и остался простым, зачем на начальном уровне что-то ещё?
1. Должен быть явный компилятор
2. Должно быть явное объявление переменных и статическая типизация
Последние года полтора я пишу код в основном на языке без этого всего, и продакшен работает. Возможно, эти концепции устаревают. С другой стороны, фаза сборки и аннотации типов присутствуют, но нужны ли они при начальном обучении?
3. В синтаксисе языка явное и заметное предпочтительнее скрытого
Эта максима почти цитирует принцип Питона "явное лучше, чем неявное". Удивительно, что по этому критерию вы выбрали Паскаль. Здесь даже Си больше подходит - в нём меньше исключений из правил. А скобки или отступы - это вкусовщина (полагаю, когда-то Гвидо сильно надоела эпическая расстановка скобок в коде и он решил радикально решить проблему).
Мощные языки обычно ближе к машинной реализации вычислений (что и является источником их мощи), а лёгкие языки оперируют более близкой к человеческому мышлению абстракцией.
Да, классически это "низкоуровневость" и "высокоуровневость", а не "мощность" и "лёгкость". Не прочитав ваших определений, я бы сказал, что Питон более мощный в смысле больших возможностей (метапрограммирование, автоматическое управление памятью и т.д.) Новые термины, выраженные старыми словами, запутывают.
В качестве языка начального уровня в 2025 году я бы использовал всё-таки Питон, а для обучения более низкоуровневым вещам - C. Также у меня теплится мысль, что для обучения может оказаться пригодным некое подмножество Rust, если не погружаться в дебри типа borrow checker, асинхронность, многопоточность, трейты.
Последние года полтора я пишу код в основном на языке без этого всего, и продакшен работает.
Зачем ссылать на свой опыт в данном вопросе? Обучение програмиированию — это Вам не "продакшн".
Возможно, эти концепции устаревают.
Нет Ничего не устаревает. Если кто-то что-то игнорирует, то это проблема игнорирующего.
С другой стороны, фаза сборки и аннотации типов присутствуют, но нужны ли они при начальном обучении?
Да, нужны. На первых порах нужно разобраться с принципами и, в том числе, приучить себя к тому, что бывают различные типы. Потом, как с колёсиком у детского двухколёсного велосипеда, можно и убрать (отказаться от).
С другой стороны, фаза сборки и аннотации типов присутствуют, но нужны ли они при начальном обучении?
Проблема в том, что в Питоне, есть определённые синтаксические конструкции, поведение которых, хотя и понятно любому питонисту и, даже, составляет выразительную мощь языка (всякие там генераторы, итераторы и декораторы), но их надо объяснять начинающему программисту. До этих вещей нужно дойти. И лучше, сначала, обойтись без. Слаще будет потом использовать. Да, конечно, можно начать и с Питона. Но тогда будет очень трудно объяснить, почему другие языки так не похожи на Питон. Настоящий программист не должен быть заложником языка программирования.
Итераторы легко объяснить, если отталкиваться не от фич языка, а от абстрактных типов данных (стандартных "коллекций" в терминах питона) - https://docs.python.org/3/library/collections.abc.html .
Когда методы разбиты по классам на логически связанные группы, как в таблице по ссылке, то в голове вместо россыпи непонимания сразу появляется вполне чёткая система. В изучении можно идти от простого к сложному, постепенно добавляя новые методы и получая коллекции с новыми уникальными свойствами (совсем как в математике).
Итератор это вообще простая штука, которая понимает всего лишь одно слово "следующий" (__next__), а когда следующего нет, то кричит "расчет окончен" (StopIteration). Можете привести ситуации из жизни, где вы сталкивались с таким протоколом? Обычно все без труда вспоминают несколько примеров.
Ни и тут кстати нюанс. Когда говорят, что в MIT теперь изучают питон, то это не совсем валидно. Программы обучения MIT по-прежнему выстроены вокруг ATD, приучая студентов видеть принципы и использовать подходящие абстракции. Но они действительно теперь проводятся с примерами на питоне. Хотя, вместо него может быть любой другой язык - он здесь абсолютно вторичен. В этом, на мой взгляд, состоит ключевое отличие от "советской" школы программирования, которая старается научить видеть за любой абстракцией уровень реализации - технику. Причем чем ниже это уровень, тем считается "круче".
Парадоксально, но для вдумчивого обучения с хорошим преподавателем очень неплох JavaScript. На нем можно очень много всего показать. Как надо писать в одном стиле, как в другом; как надо делать и как не надо. И почему именно не надо. Плюс, конечно, возможность полазить с Dev Tools по чужим сайтам, поковырять там всякое. Да и в принципе его знать надо.
Прекрасен Arduino C, за счёт своей близости к железу и того, что железо это разнообразное и очень ограниченное по возможности , что даёт возможность быстро "пощупать руками" ограничения, оптимизацию и глюки (в смысле физику)
Ну а для более самостоятельного изучения, мне кажется, неплохи вещи типа той-же Java. Сразу как-то задаёт рамки
Странно, что нигде не прозвучала тема парадигмы программирования. Я считаю, что лучше всего начинать с декларативных языков, может быть функциональных, и только потом начинать ломать мышление штуками вроде x:= x+1.
Меня в принципе радует этот новый тренд на Хабре, где практикующие педагоги делятся опытом и открывают интересные темы для обсуждения.
Проблема(?) Питона в том, что это язык, по большому счёту, для тех, кто уже умеет программировать и будет довольно урчать от синтаксического сахара. И так в нём можно, и растак, и эдак. Для подготовленного зрителя спектакль, в общем.
А для обучения людей, которые этого вашего погромирования в глаза не видели, нужны языки с большим количеством ограничений. Хотя бы затем чтобы явно неправильные и вредные паттерны не запоминались.
Можно было бы, конечно, предложить местным гуру программирования создать для нас нам новый язык программирования. Например, для обучения программированию. Очень простой. Это будет что-то вроде Бэйсика? ;-)
думаю, тут важнее быстрый старт, когда ты можешь писать с минимальным набором теории, скучных и непонятных вещей
сам начинал с BASIC еще для восьмибиток и это было идеально в плане того, чтобы максимально быстро вкатиться и понять, что такое программирование в принципе
а если ты уже понимаешь, что такое программирование, то не проблема копнуть глубже и понять, например, что такое статическая система типов
а современный аналог BASIC это Python
если брать что-то со статической системой типов, то я бы брал C#. прям идеально задизайненный язык.
Если честно, спор уже давно неактуален, индустрия свой выбор сделала. Python везде, от веба до Data Science. Pascal - в паре олимпиадных кружков и в воспоминаниях стариков.
Можно сколько угодно доказывать, что Pascal правильнее, но какой в этом смысл, если после него человеку все равно придется учить Python, чтобы найти работу?
Delphi жив, продается и развивается
Помню как в универе нас мучили Паскалем, а я втихаря писал на C++, потому что он был "круче", но сейчас я понимаю, что именно Паскаль с его begin..end и строгой структурой заложил в голову понимание блоков и областей видимости, а вот примеры кода на Python, где блок определяется отступом, у меня до сих пор вызывают легкое подергивание глаза
Сразу видно, когда происходит трансляция
Сомнительно. Ну то есть студентам обычно рассказывают, что их текст обычно происходит этап превращения в исполняемый код, но зачем от него страдать? Статичная проверка, как обычно лучше динамической, но сомневаюсь, что стоит оставлять людей без динамических проблем - возьмите тот же bash или batch в качестве примера. Заодно и про тестирование можно накинуть.
Слабое соображение, но всё-таки, скомпилированная программа, как правило, заметно быстрее выполняется.
переведите на Mojo, который синатксически тот же питон, но компилируемый.
Раздел объявления переменных позволяет проиллюстрировать рассказ о сегменте данных программы и механизмах управления памятью.
только сегмент данных никак не соотносится с нестатичными данными программы, а в паскале переменные объявляются у каждой функции, не считая входных аргументов и в большинстве случаев выоптимизированы в релизе. Разницу между стеком и кучей оно тоже слабо показывает. Можно конечно посетовать на переиспользование памяти, но это довольно слабый аргумент, ибо Cons в такой ситуации - проблема локализация ошибочных значений в таком формате тоже проблема. Дробить функции сильнее чтобы было по дяде Бобу в такой ситуации будет ещё большим злом.
Повышает дисциплину ума при программировании, формирует хороший стиль.
не все практики одинаково полезны. лучше научить считать память и уменьшать контекст проблемы в пределах области видимости.
Автопреобразование усложняет понимание программы
ровно наоборот. в большинстве случаев автоматический вывод типов помогает улучшить понимание, сжав контекст для понимания. Заодно позволяет показать класс проблем связанный с автовыводом и преобразованием типов.
Обязательное явное указание чего-то часто лучше, чем умолчание. Тут лучше пояснить на примерах, которые будут дальше.
для студента - скорее нет. вы же не можете пояснить, почему каждый раз приходится писать сигнатуры всех переменных и почему переменные у паскаля нужно объявлять в специальном блоке и почему вообще везде надо пихать эти begin end? Если вы вываливаете кучу синтаксиса, который не слишком-то полезен для реализации алгоритма, то оно становится фактором повышающим порог входа, постепенное отключение автоматизации - сглаживает кривую обучения.
print(False ** False == True)
для студента - это повод лишний раз расширить знания, но вангую, что ни один студент не сталкивался с подобными WAT моментами. Ну и во всех языках можно найти подобные квирки. Да и хорошо быть осведомлённым о некоторых пограничных кейсах, чем избегать их как класса.
И аккуратно переведём его на Pascal
в итоге маленький простенький алгоритм распух вдвое за счёт довольно бесполезных begin-endов, а спецсимволов стало примерно втрое больше (см.. ваш пункт 3.3). Улучшило ли это ясность алгоритма? Да нет. Безопасность/надёжность алгоритма это тоже не повысило - стоит отметить места типа to N-1 do, где легко сделать ошибки класс off by one - эти шишки будут набиваться постоянно и без смены подхода это не решается. Да и универсальность алгоритма на паскале заметно меньше в сравнении с питоньим, который и float типы тоже скушает и строки лексиграфически отсортирует.
аналогия между алгоритмическими конструкциями и структурами данных
стоит отметить, что Вирт опирался на математическую нотацию и паскаль во многом от этого страдает. Тот же оператор присваивания :=. Для условного школьника большая часть той нотации непонятна, т.к. в школе её в таком виде не используют, в каком она присутвует на уровне каких-нибудь undergrad студентов. В то время конечно ничего лучше не было.
как у Java (ближайшего родственника кстати)
я бы скорее назвал их соседями, нежели родственниками - родители разные, синтаксис отличный, ошибки разные, подходы разные. Из общего только работа поверх JVM и как результат импорт внешних модулей.
А из минусов Kotlin стоит отметить более функциональный подход языка - тот же pair.apply как пример. При встрече с другими языками может возникнуть определённый диссонанс.
Краткая история оператора присваивания в виде :=
Исходно (в черновиках Алгола-58, если не ошибаюсь) это была стрелка вправо, показывающая направление движения данных.
Затем стрелку переделали на =>
Потом поменяли нотацию, чтобы переменная стояла слева и сделали стрелку в виде <=
А потом, поскольку на многих вычислительных системах того времени не было знака "меньше", ее заменили на :=
То есть, это даже не математическая нотация, а что-то из серии "так сложилось исторически".
Вся нотация "исторически складывается". Однако это не кейс оператора присвоения. Он в таком виде был представлен Бэкусом в предложении по IAL, который неофициально и стал ALGOL 58.
Cf. J. W. Backus, The syntax and semantics of the proposed international algebraic language
Оператор присвоения и сравнения там уже разделены и определены на собственно := и =. Помимо этого там же использовались некоторые другие символы, в том числе и стрелочки для возведения в степень, видимо вдохновленных стрелками Кнута, стандартных операторов больше-меньше и тп. Так что стеснения вводом определённо не было и скорее всего это прихоть конкретной группы людей. Ну и языка был "алгебраическим", то бишь таки математическая нотация.
по тому же принципу из математики перекочевал оператор размера множества #. в Lua например.
procedure bubble(a: array of Integer);
begin
var n := Length(a);
var i := 0;
while i < n-1 do
begin
var j := 0;
while j < n-1-i do
begin
if a[j] > a[j+1] then
Swap(a, j, j+1);
Inc(j);
end;
Inc(i);
end;
end;
begin
const N = 10;
var a := new integer[N];
randomize;
for var i := 0 to N-1 do
a[i] := random(100);
bubble(a);
for var i in a do
write (i:3);
end.Он может быть и короче. Но отсутствие операторных скобок - это отличительная особенность только Питона и является сомнительным преимуществом.
не очень понял, что вы зовете операторными скобками. выглядит лучше, но все равно много вспомогательных вещей.
Операторные скобки - это {} или begin/end.
Но о каких вспомогательных вещах вы говорите?
Операторные скобки - это {} или begin/end.
обычно их границами блока зовут, а операторы это про всякие плюс-минус-помножить-распарсить литерал, то бишь какие-то специализированные функции, но ладно.
Но отсутствие операторных скобок - это отличительная особенность только Питона
посмотрите на haskell или lua, например. У первого вообще можно без них жить, у второго только финальная граница выражения указывается. Так что не так-то это и уникально.
вспомогательными вещами назвал все вот эти необходимые блоки begin-end не несущие достаточной функциональности для программиста, но захламляющей код. Необходимость писать границу конца выражения ;, кстати, туда же можно отнести.
Это вы сходу больше половины языков выкинули на свалку?
Операторные скобки нужны как компилятору, так и программисту, чтобы понимать где начинается один блок или область видимости и где они заканчиваются.
Без них, это каша. Вроде как отступы как операторные скобки должны прививать хорошее оформление кода, но на самом деле только ухудшают его читаемость, т.к. одном взглядом ты не определишь что в какой области видимости находится, без линейки или специальных инструментов.
П.С. Операторные скобки - общепринятое определение. Погуглите
Если нужна линейка, то функция уже слишком большая, дробите её.
На хаскеле этот подход вполне норм работает.
Дробление функции не всегда возможно и далеко не всегда оптимально. Дополнительный вызов, особенно, если он многократен - это большие накладные расходы. А если ты и в Паскале в функции будешь иметь по 5-6 строк без вложений, то разницы не будет уже никакой от Питона.
Дробление функции не всегда возможно и далеко не всегда оптимально. Дополнительный вызов, особенно, если он многократен - это большие накладные расходы.
Компилятор заинлайнит, если это важно. Ну или сами там прагму для инлайнинга навесите.
Это вот вообще не проблема.
А если ты и в Паскале в функции будешь иметь по 5-6 строк без вложений, то разницы не будет уже никакой от Питона.
Только количество церемоний и печатания вокруг создания функций означает, что этих функций у вас будет меньше, и они в среднем будут побольше.
Нет никаких церемоний. Начал писать be.. Нажал Enter - готово. В этом нет проблем. Зато есть четкая видимая область блока.
Вопрос привычки, видимо. Лично у меня нет никаких проблем с визуальным выделением блоков, даже несмотря на то, что отступы у меня в два пробела, скажем.
А вот код с кучей ключевых слов было бы сложнее читать.
Это не так. Не сложнее. Вот примеры из чатов натаскал на скорую руку.
Скрытый текст



Вот бы сейчас free руками вызывать.
Если переводить ваш код с первого скрина на хаскель напрямую, то будет что-то такое (с BlockArguments):
run
\cancellationToken -> withHttp
\http -> withStream
\response -> do
result <- get http "url"
unlessM (isCompleted result ||^ isCancelled result) $
whenM (isTokenCancelled cancellationToken) (cancel result)
whenM (isCompleted result) ({- work with response -})Скоуп точно так же виден, линейки не нужны — оказывается, если не тратить кучу строк на try / finally / end, то код становится короче, и линейки не нужны.
Дальше можно заметить, что скоупы-то совпадают, поэтому не нужно расти вправо:
run
\cancellationToken -> withHttp
\http -> withStream
\response -> do
result <- get http 'url'
unlessM (isCompleted result ||^ isCancelled result) $
whenM (isTokenCancelled cancellationToken) (cancel result)
whenM (isCompleted result) ({- work with response -})Правда, на хаскеле никто так не пишет (потому что можно просто прибить тред), и та же задача решалась бы примерно как
run $ withHttp
\http -> withStream
\response -> do
result <- get http 'url'
case status result of
Completed -> {- work with response -}
Error -> {- handle error -}Правда, вообще непонятно, зачем тут response, но неважно.
У вас максимально не читабельный код. Вы дословно поняли код на Паскале, а вот эту мешанину символов я понять полностью не могу. А ведь у меня много опыта и не только на Паскале, но и в Питоне и в С# и даже в Плюсах есть.
Если человек, освоивший набор скиллов A, может понять скиллы из множества B, а человек, освоивший B, понять A не может, то что это говорит о сравнительной мощности скиллов?
Это говорит о том, что первый язык легко читается любым человеком, а второй, без дополнительной подготовки именно в этом языке, не читабелен. Если знания Паскаля применимы в понимании программирования в целом, то знания Хаскеля применимы только к Хаскелю и больше ни к чему вообще.
Это говорит о том, что первый язык легко читается любым человеком, а второй, без дополнительной подготовки именно в этом языке, не читабелен.
Я в своё время для отца делал разные вычислительные эксперименты, и, короче, код на хаскеле ему читать проще (и убеждаться, что именно там происходит, и соответствует ли оно его модели), чем на плюсах. Притом, что у него за спиной опыт фортрана в его годы, а опыта ML-подобных языков нет.
Если знания Паскаля применимы в понимании программирования в целом, то знания Хаскеля применимы только к Хаскелю и больше ни к чему вообще.
Ну вот вы паскаль знаете, а хаскель не смогли прочитать. Я паскаль не знаю, а прочитать его смог. Так что эмпирически дважды нет!
TTask.Run(
procedure
begin
var HTTP: IHTTPClient := THTTPClient.Create;
var Request := HTTP.BeginGet('url');
while not Request.IsCompleted and not Request.IsCancelled do
if Task.CurrentTask.Status = TTaskStatus.Canceled then
Request.Cancel;
if Request.IsCompleted and not Request.IsCancelled then
begin
// work with Request.Response
end;
end);Код можно переписать так. Response там действительно не нужен. Я не разглядывал что брал из чата, это видимо с багом код был.
Здесь тред берется из пула и управляется дефолтным пулом. Завершение программы не приведет к краху. Пул будет остановлен в штатном режиме. Без ожидания ответа от сервера.
Кода не сильно больше, даже с учетом begin/end. И что самое главное, этот код читается по словам.
И что самое главное, этот код читается по словам.
Только для того, чтобы убедиться, что while делает то, что нужно, уже надо построить нетривиальный граф выполнения в своей голове.
Ассемблер ещё больше читается по словам, в конце концов, но это не делает его проще.
While тут: пока запрос не завершился и пока не отменился делать: если задачу отменили, отменить запрос. Всё. Я прочитал это дословно
Для этого нужно как минимум понимать, что статус задачи — мутабельное поле, и имеет смысл его спрашивать снова.
Кстати, это busy loop, что ли? Лол. Узнаю запах старой школы.
Программа читается так: пока запрос не завершился и не отменен, трать как можно больше тактов процессорного времени на проверку внутреннего условия.
Может быть, в паскале и вставляется задержка перед проходами цикла, но из текста она не очевидна. Любой, знакомый хотя бы с C, моментально захочет вставить в тело цикла задержку в некоторое количество миллисекунд.
Вывод: плохой язык, программа работает неочевидным образом, либо язык так и не смог научить своего пользователя контролю за процессорным ресурсом.
Pascal ABC так не умел раньше. Да и RAD вроде только с третьего символа подсказки показывал. Экономия в символ на каждый begin - ну такое.
На хаскеле этот подход вполне норм работает.
Даже прекрасно работает. Читается еще хуже, чем лестница операторных скобок =)
Операторные скобки - общепринятое определение
насколько я понимаю, операторные скобки как термин присутствуют только в наследниках алгола, то есть в тех языках, что используют ключевые слова для определения границ блока - в частности и паскаль с begin-end. Для Си-подобных языков операторными скобками зовутся обычные () и отношения к блокам кода они не имеют. Не знаю относятся ли к этой категории какие-нибудь шеллы с их if fi и ады-фортраны с их endloop endfn и прочими.
Операторные скобки нужны как компилятору
Собственно это основная причина. И то насколько простым хочется сделать компилятор. Паскаль вроде как подразумевает однопроходный компилятор и поэтому все, что не входит в трансляцию в машинный код и оптимизации, ложится на плечи программиста, включая явно определение типов, явное определение границ блоков и много чего ещё.
Haskell и OCaml на одних переносах могут жить. Lua и Ruby хотят только знать где конец, ибо знают какое выражение было начато - казалось бы структура паскаля тоже достаточно проста, чтобы понимать это, однако же так не делает. С#, JS и Rust могут не требовать границ блока, если выражение достаточно тривиальное - например вызов лямбды или определение нетривиальных сеттеров.
без линейки или специальных инструментов
у меня всегда вызывает вопрос а в какой такой ситуации люди находятся, что им приходится заниматься разработкой, имея только компилятор и минимальный блокнот и ничего больше из спец.средств. Я конечно понимаю, что tree sitter относительно недавнее изобретение и раньше даже подсветка синтаксиса за пределами набора ключевых слов были дорогим удовольствием, но что заставляет людей из сегодняшнего развитого окружения возвращаться к состоянию того времени - для меня загадка. Так что совершенно не разделяю вашего мнения касательно ухудшения читаемости. Даже в ситуации когда включен word-wrap и строчка оказалась длинее 160 символов.
Но отсутствие операторных скобок - это отличительная особенность только Питона и является сомнительным преимуществом.
Python, Haskell, F#, Scala 3... Скобки или отступы - вкусовщина, всё равно отступы принято делать.
Как самоучка конца 80-х свидетельствую: Паскаль - отвратительный для обучения язык. Он все время бьет тебя по рукам, когда ты хочешь что-то сделать. Он требует заранее все продумать - при том, что в новых задачах это в принципе невозможно.
Для меня удовольствием было писать на ассемблере MACRO-11 и нудной обязанностью - на Паскале.
Паскаль - антитеза любого творчества в программировании. Он годится только для бухгалтеров.
Но вашим ученикам бежать некуда и выбора у них нет, они могут лишь молча терпеть это BDSM.
Он заставляет думать, думать заранее, прежде чем пишешь код. Да, иногда это мешает.
Но учит активно думать головой. И да - думать это больно! (с)
А что, для программирования на других языках не надо думать?
А вот тут есть одна забавная деталь - когда вы можете писать код сразу, не задумываясь о результате, то код получается так себе зачастую. Потом приходится всё переписывать.
И этим часто страдали сишники. Обратите внимание - почти все опытные паскалисты ушли в более крупные сферы - как правило в архитекторы, и ушли успешно. А вот в С++ они не рвались, сразу увидели тупик для дальнейшего развития.
Плохой код и навыки можно улучшить. А вот нудным Паскалем навсегда отбить детям желание что-то делать - это запросто.
Чтобы вызвать интерес к программированию, человек должен чувствовать себя хозяином машины, а не ее рабом.
Чтобы вызвать интерес к программированию, обучение должно быть интересным. И желательно, чтобы обучаемый сразу видел какой-то внятный результат. И я не могу назвать интересным то, как обучали меня. Но это было очень давно. Сейчас есть лругие варианты и языки для этого.
Открываешь среду разработки Delphi у тебя уже готовая программа, которую можно запустить и передать другу, чтоб он её запустил. А кинул кнопку и два раза щелкнув по ней ты уже пишешь код, который будет вызван по этой кнопке, например с показом сообщения (1 строка). Да ещё и на андроид собрал одним кликом и скинул друзьям. Кинул компонент "камера" на форму и вот у тебя уже возможность захватывать кадры с камеры телефона с быстрым накладыванием эффекта на этот кадр (просто кинул на форму компонент с шейдером). А если кинуть на форму компонент для работы с БД, то можно уже сохранять что-то типа заметок в sqlite бд, которая встроена в каждый Андроид (и я не использовал тут ничего стороннего, всё в поставке).
Интерес зависит от преподавателя, а не от инструмента, а Delphi даёт сильно больше простых способов вызвать этот интерес, т.к. у него всё идет из коробки.
Ну вы загнули конечно, сразу давать ассемблер защищённого режима x86 с кольцами безопасности. Но я согласен - студентам это было бы полезно прочувствовать на себе :-)
Ну есть такие, что голову сломаешь, прежде чем напишешь - вроде Лиспа :-)
Но я про то, что можно писать более структурированный код и Паскаль это позволяет.
А можно спагетти код - и на с это делать чуть легче, чем на Паскале.
Хотя разница формальная конечно.
Паскаль - отвратительный для обучения язык.
Любой язык отвратительный, если нет хорошего учителя.
Он все время бьет тебя по рукам, когда ты хочешь что-то сделать
Любой язык так себя ведет.
Он требует заранее все продумать - при том, что в новых задачах это в принципе невозможно.
Писать код не думая раньше нельзя было на любом языке.
речь то не о творчестве, а об обучении =)
ассемблер pdp-11 весьма приятный, можно его преподавать в дополнение, не такой кривой как x86. но планировать в нем тоже было надо - не так много регистров
Но вашим ученикам бежать некуда и выбора у них нет, они могут лишь молча терпеть это BDSM.
А ещё могут нагуглить какой-нибудь питон и потом учить паскаль с полным осознанием что это БДСМ морального устаревания преподаваемых тем...
Паскаль морально стар, уж лучше окунуться с головой в плюсы, имхо, так можно более базовые вещи изучить на довольно высоком уровне, так что при переходе на другие ЯП это будет ощущаться, как любят говорить динозавры из вузов, "как семечки щелкать"
Современная Delphi не так далеко ушла от С++20, как может показаться.
А чем он морально стар? Ну, в чем это проявляется?
Ну как умение ездить на лошади. 2 лет назад - необходимость. Сейчас - забавное хобби.
на нём никто не пишет, кроме школьников учитель у которых не знает питон (что нормально, учитывая зарплату учителя информатики по сравнению с зарплатой программиста). Посмотрите статистику использования языков на школьных олимпиадах, или на ICPC, там превалируют python и c++. Это – школьный стандарт.
Он решает те же задачи, что и Питон. В чем именно он устарел?
но питон проще, и на нём проще написать свою первую сортировку, первый поиск по графу, меньше отвлекаясь на особенности конкретного языка, думая больше про алгоритм. Паскаль в этом мире оказывается просто не нужен.
Это заблуждение. Конструкция "свапа" в Питоне никаким образом не является логичным решением и никак без знания этого языка в голову не придет. А вот алгоритм "положить значение во временную переменную, а затем заменить новой и вернуть из временной" - это логичное и простое решение. Паскаль намного более человекоподобный язык, чем Питон, что упрощает написание.
Потому что ты его читаешь дословно, а не додумываешь слова.
if/then/else - если/то/в противном случае
while Х do - пока Х делать
for var i in Arr do - для переменной i в массиве Arr делать
И так со всем кодом. В том числе операторные скобки. Тут начинаем, а тут заканчиваем.
причём тут конструкция свапа? Задачки на «поменять местами значения a и b» есть в стандартном школьном сборнике задач по питону, с припиской не использовать кортежи, и школьники её правильным образом решают. Также как задача на написание сортировки идёт с припиской «не использовать sort». Вы выдумываете проблему.
А вы выдумываете некую простоту Питона, которой нет, без такого сахара. Чем на Питоне написание алгоритма проще?
почему сахар не делает язык проще? Индустрия не случайно выбрала питон и убила R и Julya. Нам же нужно чтоб дети выражали на языке алгоритм работы с данными, а не с регистрами.
Сахар есть и в Паскале, вы о нем просто не знаете. Так же, как новички не знают о сахаре в Питоне. Все алгоритмы изучаются без какого-либо сахара. В этом и есть смысл обучения.
А питон менее понятен и с сахаром и без.
и всё же объявление переменной нужно только компилятору, понятнее от этих строчек язык не становится
Становится. Переменная - часть любого алгоритма, которая должна быть строго определена.
видите какой питон хороший: в нём то все переменные строго определены, а не просто заданы. Для каждой переменной сразу видно, зачем она нужна.
О чем вы вообще? Об инлайн объявлении? Типа:
begin
var i := 122;
var s := 'text';
var a := [1, 2, 3];
end;Ну так используйте это и в Паскале. Кто вам мешает.
Это сахар. Но ведь вы не будете говорить школьникам писать алгоритмы без этого сахара? Зачем?
Переменная - часть любого алгоритма, которая должна быть строго определена.
Нет, конечно, это не так.
Объявляю алгоритм обмена значений как морфизм A × B → B × A, описанный как ⟨ π₂, π₁ ⟩. Здесь нет никаких переменных (ни временных, ни постоянных, никаких), при этом это вполне строго определённая формальная категориальная конструкция.
Очень интересно увидеть поиск по графу на Питоне, не отвлекаясь на особенности конкретного языка
если школьники готовы к продвинутому изучению программирования, не для общего развития, а для поступления потом на соответствующую специальность, им можно помимо питона давать подмножество c++. В ЛКШ это просто работает.
кажется что практика последних лет 20 в России показала, что python это лучший язык для обучения школьников программированию, по крайней мере в профильных физмат классах. Цель при этом обучить алгоритмам, и немного рассказать про устройство процессора. При необходимости, для участия в олимпиадах, легко выучивается подмножество c++, чтоб программы работали быстрее.
питон это тупик для обучения. потому что выучив питон, кажется что больше ничего и не нужно =)
а поняв недостатки паскаля, учатся дальше - хоть питону, хоть плюсам, хоть чему императивному
так может если школьник не хочет становиться программистом, а хочет быть каким-нибудь ML-инженером, ему ничего кроме питона в жизни и не нужно, в смысле никакой другой ЯП? А вот если школьник действительно способный, он пойдёт писать олимпиады, где быстро выяснит что питон медленный, и начнёт писать на актуальном c++. Мёртвого паскаля в этой схеме нет, он никому не нужен, кроме стариков вспоминающих свою молодость :)
с таким подходом он вылетит с олимпиады, потеряв год учёбы и год до следующей олимпиады и пойдёт в ии-вайб подсказчика =)
ML-инженер это не вайбкодер, если что. Выход в интернет на олимпиадах, естественно, ограничен, хочешь подсмотреть какой-нибудь готовый стандартный алгоритм – распечатай его заранее.
Школьников-олимпиадников - незримо малое множество. Олимпиады - это хорошо, но они - не про "научиться программированию". А в тексте статьи - ровно про это
У Паскаля есть наследники: Delphi и опенсорсный Free Pascal. Эти языки актуальны, развиваются и используются в разработке. Они оба кроссплатформенные. Delphi - проприетарный язык и инструмент, имеет Community версию среды разработки, позволяет собирать графические приложения под все платформы в том числе iOS и Android. Поддерживает разные бэкенда отрисовки UI. От GDI, DirectX и OpenGL, до Skia и Vulkan
не, вообще не актуальны, работы на них практически нет. С питоном, который из-за простоты стал и языком ML, и языком математиков, и языком девопсов/сисадминов, не сравнится. Не случайно где-нибудь в ШАДе учат только python/c++.
Работы на нем больше, чем на Rust или Swift. А не в России, в некоторых странах на порядок больше чем на C# или Go.
Питон - да, лидер попсы. А девопсы и математики - не программисты.
Работы на нем больше, чем на Rust или Swift.
Бегло посмотрел на indeed — на rust 1000+ вакансий, на паскале — около 50, на delphi — 24 (все с фильтром зарплаты 50+ в год, чтобы убрать поваров в Pascal's Pizzeria).
А не в России, в некоторых странах на порядок больше чем на C# или C++.
А можете назвать эти страны?
Бразилия, например
Мне лень разбираться с бразильским рынком и узнавать, какие там агрегаторы самые популярные, и потом ещё переводить с/на португальский язык, поэтому я позволил себе спросить у chatgpt. Chatgpt говорит:

Похоже, осетра с «на порядок больше» всё же стоит урезать.
Вакансий на HH:
Delphi: 92 (0) ~126k (30-370)
Pascal: 37 (0) ~70k (10-280)
Python: 2240 (0) ~80k (20-350)
C#: 991 (+1) ~120k (25-350)
C++: 1648 (0) ~120k (5-600)
Swift: 224 (+5) ~180k (60-350)
Java: 1276 (0) ~120k (40-350)
Visual Basic: 36 (+1) ~110k (33-350)
Go: 631 (+2) ~160k (40-250)
Ruby: 96 (+2) ~70k (70-300)
Kotlin: 491 (+1) ~145k (1-400)
Rust: 117 (+3) ~150k (60-600)
Fortran: 3 (0) ~50k (50-50)
Dart: 103 (+3) ~120k (0-280)
Flutter: 190 (+4) ~120k (60-400)
FireMonkey: 1 (0) ~300k (300-300)
Electron: 43 (+1) ~100k (70-350)
Lazarus: 3 (0) ~50k (50-80)
React Native: 163 (-2) ~120k (1-300)
FGX: 0 (0) ~0k (0-0)Такая вот статистика собирается с HH.
вместе с Ruby и Dart, язык мёртв. А вы предлагаете массово учить этому школьников, которые ещё и программистами потом не станут. Напротив, python нужен в итоге всем. По крайней мере бекендерам.
Мы переписыаем бэкенд с питона на делфи, т.к. заказчика не устраивала скорость и стабильность работы решения на Питоне.
Переписано два из трёх крупных бэкенда.
Почему не на go? Индустрия говорит переписывать на go. Вы странные. Вы как потом программиста на делфи достанете, некромантом?
Разработчиков на Делфи хватает. А бэкенд пишется ни чуть не хуже, чем на Го. Около десятка бэкенд фреймворков разной сложности имеется.
Зачем нам нанимать отдельный штат разработчиков на Но, если есть уже большой штат Делфи разработчиков?
Питонистов штат набирали - вышел шлак. Переписываем.
хватает? Какой вуз их нынче готовит? Впрочем теперь понятно, почему вы так защищаете мертвичину)
На официальный сайт языка зайдите. Посмотрите дату последней публикации очередной версии. Язык и инструменты не стоят на месте.
Я защищаю, потому что вы пишите полную глупость. Потому что я знаю как у него обстоят дела. И на рынке разработчиков и в стенах разработки языка и инструментов. Вы же, пытаетесь назвать язык "мертвым", не зная абсолютно ничего и текущих делах языка.
нет, правда, смиритесь с тем что icpc пишут исключительно на python/c++, а значит и школьников с уклоном в программирование успешно учат python/c++, а затем со сменой учебных пособий на актуальные (школьники год от года учат всё больше и больше в программировании) все школьники пересядут на python. Это прогресс.
Мы переписыаем бэкенд с питона на делфи, т.к. заказчика не устраивала скорость и стабильность работы решения на Питоне.
А сравнивали с С++ или Rust? Я как-то переписывал с Delphi на С, и разница в скорости была 10 раз (!) только за счёт оптимизирующего компилятора.
В Delphi у меня имеется и высокая скорость работы и высокая скорость написания кода. Я использую десериализаторы, рефлексию, DI, таски и асинхронную обработку в пару строк. И всё это из коробки, здесь и сразу.
Разницы в 10 раз можно получить видимо на каких-то частных задачах, типа векторизации. В общем и целом Плюсы быстрее не более чем на 10-20% и то не всегда.
Delphi для нас оказался балансом между удобством и скоростью
Это какой то крайний случай. Разница между компилируемыми языками обычно не такая большая, ну раза в 3 максимум (ну еще векторизация).
А Дельфи сейчас переехала на LLVM так что вообще разницы может не оказаться с тем же растом или цлангом.
в скорости была 10 раз
скорее всего это значит, что исходный код на Delphi был не очень качественным и переписанный код качественно отличался. То бишь явно не 1-в-1.
А сравнивали с С++ или Rust?
Бэкэнды на плюсах писать довольно больно, а для Rust потом придётся искать людей поддерживать эту систему - не сказать чтобы специалистов достаточно, чтобы закладывать подобные риски.
Как набрали? У меня оно номер телефона требует, которого у меня нет, а без него я могу только посэмплировать выборку. Сэмпл получается прикольный. Вбил pascal, получил те же 37 вакансий. Тыкнул в первую же, а там паскаль упоминается только в ключевых словах. Требования: «знания QT, CoCox, Quartus, Verilog, экспертные знания C++» ох уж этот QuickTime вместо Qt. Про паскаль ни слова.
В другой вакансии, окей, паскаль и бейсик. Кстати, сколько бейсика, если не фильтровать по visual? 74 вакансии. Очень живой язык, видимо, Почти до дельфей дотягивает.
https://github.com/HemulGM/HH_Delphi_Stat/blob/main/hh_delphi_stat.dpr#L113
В первой вакансии указаны навыки Borland Delphi, Delphi, Pascal
Basic - не факт, что про язык. Возможно что-то типа Basic SQL или что-то вроде
Кстати, сколько бейсика, если не фильтровать по visual? 74 вакансии. Очень живой язык, видимо, Почти до дельфей дотягивает
Кстати показательно. А что, есть спецы, не умеющие программировать на бейсике?
Т.е. как бы не популярен, потому что основа.
А что, есть спецы, не умеющие программировать на бейсике?
Не умею программировать на бейсике.
Не умею программировать на бейсике.
Что же вызывает у Вас затруднения? Давайте поговорим об этом.
Понимаю, бывает конечно трудное детство, заставляли в Лисп или Форт, трогали Хаскелем или же учили Прологом =)
Очень многое зависит от глубины восприятия и степени вовлечённости среди слушателей. Не существует методов преподавания, одинаково эффективных для каждого. В ряде случаев очень эффективно было бы рассматривать параллельно сразу два языка, чтобы понимать какие процессы, в каком виде и для каких целей происходят. Такой подход быстрее поможет уловить логику и отточить дисциплину.
Я, имея за плечами пару десятилетий стажа программирования, за старый Pasсаl всеми руками и ногами для начинающих маленьких программистов - он учит логике, там всё чётко и понятно, если у человека есть логическое мышление. Если бы я с Python начинал обучение, а не Бейсика и Паскаля, то наверное забросил бы этим заниматься почти сразу - синтаксический сахар и некоторые неочевидности без надлежащей подготовки могут ввести в полный ступор того кто начинает учиться той логике, которая лежит в основе программирования, кмк. Для маленьких программистов нужно всё предоставить максимально и логично. Полноценный язык программирования — это система, в которой можно выразить любой алгоритм, т.е. язык должен быть Тьюринг-полным. Чтобы язык мог выполнять любые вычисления, в нём достаточно реализовать три вещи:
Хранение состояния
– переменные, память, стек, регистры — что-то, где можно хранить данные и изменять их.
Пример: x = 5
Ветвление (условные переходы)
– возможность проверить условие и выбрать путь выполнения.
Пример: if x > 0 then ... else ...
Повторение (циклы или рекурсия)
– способ повторять действия до достижения условия.
Пример: while x < 10 do x:=x+1 (конструкция x++ - это уже синтаксический сахар, не сразу доносящий происходящее событие, как мне кажется. И тут "x:=" гораздо более очевидная конструкция чем "x=" в некоторых языках, которую можно понимать двояко )
Даже минимальный язык, у которого есть переменные, условие и цикл (или рекурсия), уже Тьюринг-полон.
И больше ничего лишнего не надо навешивать на неокрепшую юную/(а может и повзрослее) психику. Потом, когда зародится понимание и проснется интерес, сам начнет искать другие более навороченные решения.
В целом с посылом статьи согласен, хотя не под всеми аргументами готов подписаться.
У Столярова, которого тут уже упоминали, была занятная статья про то, почему нельзя использовать С/С++ в качестве первого языка программирования http://stolyarov.info/files/anti_c_v03.pdf. Мне кажется, посыл "Хак как стиль мышления вреден при обучении" применим и тут.
То есть фишка в том, что да, паскаль старый, и полученный опыт вряд ли будет полезен в смысле резюме. Но тем не менее, полученные навыки как-то так влияют на мозг программиста, что у него есть шанс стать хорошим инженером. Может быть, наличие типов данных, о которых никто за тебя не подумает, может быть указатели, черт его знает.
Но не могу согласиться, что само по себе наличие компилятора как-то влияет. Да и типы данных.. В паскале они просто есть. Мой любимый хаскель, где компилятор решает уравнения относительно типов (потому что есть алгебра типов как таковая), тему типобезопасности раскрывает куда лучше. Нужно ли его давать как первый язык программирования? Да ни в жизни :-)
Кстати, котлин после хаскелля восторга вообще не вызывает. Просто чуть симпатичнее джавы (да и то местами).
Преподаю программирование более 10-ти лет. И у меня уже давно сложилось свое определенное мнение на счет того, какие из языков программирования в настоящее время наиболее подходят для этого. Помню, как у меня как-то одна дама в разговоре спросила: Хочу сына отправить учить программирование. Не подскажете, какой язык сейчас самый модный? Никогда не оценивал языки программирования с этой стороны до того момента...
Вообще довольно-таки странное ощущение от языка, автор которого долгие годы боролся с оператором goto, но так и не смог от него избавится в своем самом известном языке программирования.
Программирование - это достаточно сложный вид деятельности. Даже без явного использования типов. И обучающемуся в самом начале будет гораздо проще освоить присваивание, условия, циклы и функции и начать работать с ними без понимания того, что где-то там внутри у каждого значения есть свой конкретный тип. Плюс желательно иметь возможность объявить перенную как можно ближе к месту ее первого использования. И обе эти вещи не про Pascal, который к изучению логики работы кода сразу добавляет головную боль в виде типов и того, что переменные объявлены неизвестно где.
Еще одной проблемой Паскаля является отсутствие его практического применения в настоящее время на реальном проекте хотя бы для самого себя. А считать сферических коней в вакууме очень быстро надоедает. Обучающийся должен иметь возможность сделать что-то, что он может показать другим или как-то использовать сам. Плюс отсутствие современных удобных сред разработки, которые эту самую разработку существенно упрощают. Ну и, соответственно, возможность применения полученных знаний для последующей трудовой деятельности и зарабатывания денег себе на пропитание после изучения детища Вирта околонулевая. И все изучающие Паскаль очень скоро это понимают. И им становится просто скучно и не интересно заниматься дальнейшим изучением этого языка. И поэтому, с моей точки зрения, Паскаль - не очень подходящий вариант для изучения программирования.
Вы можете возразить: так он же специально создавался для обучения программирования. Но задайтесь таким вопросом: А какие еще были варианты в то время, когда Вирт его создавал, чтобы учить своих студентов? Бейсик? Алгол? Фортран? Ну или еще Кобол. Давайте вспомним, что тогда еще не было даже Си. Они создавались где-то в одно и то же время. И по сравнению со всеми вышеперечисленными языками, которые существовали на то время, я согласен, Паскаль вполне себе выигрывает для обучения программированию.
Однако сейчас есть много хороших современных языков намного более подходящих для этой цели. Причем, выучив один из них, мы можем вполне себе что-нибудь осязаемое на нем сделать.
С моей точки зрения два наиболее подходящих кандидата - это Javascript и Python. Низкий порог входа, пологая кривая обучения, возможность практического применения прямо со старта изучения и удобные современные среды разработки - их несомненные плюсы.
Научится человек использовать присваивание и другие возможности этих языков, поймет, как работают условия и циклы, уложится у него в голове все это, и вполне потом может двигаться дальше к чему-либо со строгой типизацией типа Си или Java. Если ему это нужно, если захочет или если он это будет использовать в своей практической делятельности. Ну и несомненно, профессиональный программист должен хорошо знать что такое типизация и уметь работать с типами.
Мы все учили в школе, а потом и в университете математику. Вот только никто из нас не начинал ее изучение с интегралов. И никто не изучал производные параллельно с элементарным сложением. Сначала было сложение 1 + 1, потом через некоторое время вычитание 2 - 1. В следующем классе или через класс - умножение 2 * 2 = 4. И только через годы логарифмы, а потом и интегралы.
Поэтому я считаю, что Javascript и Python - вполне себе подходящие для целей обучения кандидаты. Хотите что-то статически типизированное - Си, Java или C#. Ну уж точно не Pascal, который даже его автор всю свою последующую жизнь пытался улучшить и сам не считал идеальным языком.
Паскаль - не очень подходящий вариант для изучения программировани
Паскаль - отличный вариант для изучения программирования на Паскале ;) Использовать его по назначению можно чуть менее чем нигде (на олимпиадах, ага). Шаг в сторону где деньги платят - и надо заставлять себя писать = вместо :=, == вместо =, {} вместо begin/end. Плюсы ничем не сложнее паскаля, но хотя бы не нужно переучиваться. Все равно что учиться ездить на механике с правым рулем, чтобы переучиваться на леворульный автомат.
В разработке на десктоп или мобильные платформы. В чем угодно из сфер. От работы с большими числами и CUDA, до рендеринга и игр. Нет у него ограничений, а есть все нужные библиотеки. И для работы с OpenAI и прочими сетевыми обёртка и, с SDL и Vulkan, средства отрисовки графиков и отчётов вообще встроены, работы с любыми БД, с выводом и редактированием - тоже. Даже с S3 встроена библиотека.
Для мобильных платформ два фреймворка: штатный с собственным UI и для нативного UI.
Ну, можно конечно для себя писать что угодно на чем угодно. Но если в конторе весь стек на плюсах - знания Паскаля никак не помогут.
Ну так в этом случае и знания Питона не помогут. Скорее даже навредят.
Речь ведь об использовании языка и об обучении на нем программированию. Паскаль, в современных его представлениях позволяет решить любые современные проблемы, так что проблем с этим я не вижу.
Ну там кто то размахивал табличкой с количеством вакансий. Чем язык популярнее - тем проще найти работу. И проще поменять.
Паскаль, в современных его представлениях позволяет решить любые современные проблемы
И для ML годится? Есть ли инструменты типа Jupyter Notebooks, библиотеки типа pytorch?
Еще одной проблемой Паскаля является отсутствие его практического применения в настоящее время на реальном проекте хотя бы для самого себя.
Написать свой мобильный клиент ChatGPT для Андроид? Свой кроссплатформенный музыкальный плеер, который авторизуется в Google Drive и даёт онлайн доступ к личному диску с музыкой? Может свой личный TOTP Authenticator, аналогичный гугловому и микромягких? А может генератор/сканер QR? А может приложение на иос для просмотра 3D панорам в 20 строк? Вперёд. Пишите.
Всё то, о чем я написал выше есть у меня в открытом доступе на GitHub
https://github.com/HemulGM
Плюс отсутствие современных удобных сред разработки, которые эту самую разработку существенно упрощают.
А официальная среда разработки наследника Паскаля не достаточно современная и удобная?
https://www.embarcadero.com/products/delphi
К сожадению, так и есть - не достаточно современная и удобная. Я пробовал работать в C++ Builder после Visual Studio или IDE от JetBrain. По удобству небо и земля совсем не в пользу наследника Delphi. Да и Delphi это у же не совсем Pascal.
Delphi - это продолжение Паскаля. Нет просто Паскаля уже несколько десятков лет. Из Паскаля вышел Object Pascal, который в дальнейшем просто переименован в Delphi, а также от Object Pascal отпачкован Free Pascal.
По этому нет никакого смысла говорить о просто Паскале, это всегда должна быть актуальная его версия. Иначе можно говорить, что С++ тоже не надо изучать, т.к. стандарт C84 устарел.
Вы можете возразить: так он же специально создавался для обучения программирования.
Паскаль НЕ создавался для обучения. Он отлично подошёл для обучения. Это совсем разные вещи.
Вы действительно похожи на преподавателя, который помнит только то, что когда-то сам давно изучал. А о современных реалиях вы мало что знаете.
Паскаль не заброшен, у него есть современное продолжение в виде Delphi и ответвление в виде Free Pascal. Оба этих языка развиваются и обновляются регулярно. В том числе развиваются и инструменты для них.
Давайте лучше скажем, что у него было в свое время продолжение в виде Delphi, лучшие времена которого закончились с окончанием эпохи Delphi 7. А то, что есть сейчас, да оно развивается как-то, да, там добавляются новые фичи. Может его кто-то даже и использует. Вот только как и где? В Вашем городе много работы на Delphi или на Free Pascal? Или Вы состоите в каком-то серьезном большом быстро развивающемся сообществе этого языка/среды разработки? Или есть какие-то курсы, которые проводятся по этому продукту? Я думаю что нет.
Есть и сообщество и курсы и вебинары и были (вебинары) даже на русском, до некоторых событий в стране. Есть открытая система заявок. Есть ЗБТ. И да, в нашем городе есть вакансии.
Что-то мне Паскаль начинает напоминать религию, после прочтения комментов от почитателей.
Вот вам тут заминовали, но я хотя моя рука тянется к пистолету, когда я вижу "Javascript" в общем-то даже согласен, что если цель дать какие-то общие, поверхностные представления о программировании, то эти языки подойдут.
С другой стороны я не очень понимаю что такого сложного в понятии типа, что оно может стать непреодолимой преградой. Тип это такое свойство объекта, которое говорит:
Как он хранится. На это можно закрыть глаза до поры до времени, жахать сразу всякими хэш-таблицами неокрепшие умы, наверное, не стоит. Хватит поверхностного понимания вроде "ну вот есть адрес в памяти"
Какие данные может хранить объект. Ну там целые числа, вещественные или символы. Ничего очень сложного тут нет, уж целые числа отличать от дробных или цифры от букв способны люди уже в младшей школе.
Какие операции допустимы для объекта. С этим, кажется, тоже никаких проблем не должно быть: на той же математике или уж тем более физике все уясняют, что смысл в действиях есть только для однотипных объектов, например; а операции, осмысленные для одних объектов, могут не иметь его для других.
Таким образом мы, возможно, получаем простоту на начальном этапе, но вместе с тем прививаем и вредные привычки. А заодно не рассматриваем некоторые важные детали, превращая программирование в некотором роде в произнесение заклинаний (это, впрочем, касается любого синтаксического сахара)
Мне кажется, что разменивать глубину на простоту в общем случае неверно.
Нет цели дать поверхностные знания. Есть цель с чего-то начать и быстро применить. И не дать погаснуть интересу к предмету изучения. И если во время начала обучения обучаемый думает только о логике работы его кода, ему гораздо проще начать что-то писать, чем если ему еще нужно думать и о типах на этом этапе. Сначала пусть подумает и поймет как это работает. И сам сделает что-то работающее. Потом мы можем добавить и типизацию. И много чего еще.
Обучение должно быть постепенным. Шаг за шагом. А многие глядят с высоты своего опыта и не понимают, или скорее уже забыли, что изучить новый для себя язык программирования намного проще, когда у тебя в багаже есть уже один или несколько других, чем в принципе начать изучение программирования. Что концепция присваивания - сама по себе далеко не тривиальная вещь. Что циклы и условия - это не то, с чем обычный человек работает каждый день. И надо еще уложить все это в голове и заставить работать в совокупности. А если сразу на все это навесить типы, понимание резко становится намного сложнее.
Статья об обучении программированию, а не о написании промышленного энтерпрайз кода. И мой коммент был об обучении программированию. Скорее даже о самом его начале. И о практическом применении полученных знаний с получением за это практическое применение оплаты.
Вакансии на Pascal/Delphi - их в моем двухмиллионном городе почти нет. Для джунов - нет от слова совсем. Что изучавший Паскаль будет делать после окончания его изучения? Где он сможет применить на практике полученные знания? На пет-проектах? А что потом? Сразу переучиваться на другой язык? А почему в таком случае не начать с этого другого языка и не изучить все необходимые концепции на нем?
И да, я действительно, в отличие от многих здесь, думаю об изучении программирования именно как преподаватель этого самого программирования, а не только как программист.
Оно-то в общих чертах да, но на практике нет.
Я вот когда в 12 или 13 лет начал учиться программировать, то у меня никаких проблем с типами не возникло. Ну типы и типы.
Но ладно, возможно мой опыт нерелевантен, я сам захотел, и у меня была мотивация потерпеть какие-то вещи. Может с другими людьми не так?
Да вроде бы всё так. Я вот преподавал в школе, и могу сказать, что в нельзя утверждать, что паскаль по сравнению с питоном вызывает какое-то ужасное отторжение и неприятие. Никаких двадцатислойных абстракций не нужно для понимания типизации. Для циклов и условий тоже. А умея работать с переменными, циклами и условиями уже можно некислое количество задач решить, в том числе олимпиадных.
Опять же, не нравится вам паскаль в силу его неактуальноти (тут я не берусь утверждать, но выше и ниже в комментариях утверждают, что ситуация далека от однозначности) -- пускай будет какой-нибудь С++ или C#.
Так или иначе, по итогам преподавания разных языков и в школе, и в университете, я должен сказать, что большое количество синтасического сахара, как и какие-то неявные преобразования скорее вредят. Они полезны практически, да, но только людям, которые имеют представление, как оно там внутри работает. А если человек привык что ну оно там само как-то поймёт что за типы, то потом его будет ожидать неприятный процесс вкорячивания понятия типов в своё представление о программировании. Уж лучше пусть сразу с ним живёт.
Опять же, вот вы сами приводите питон как подходящий вариант для первого языка. А как вы на нём-то научите человека писать программы не вводя понятие типов? Ну вот буквально задачу "Примите два числа, выведите сумму"?
И да, я действительно, в отличие от многих здесь, думаю об изучении программирования именно как преподаватель этого самого программирования, а не только как программист.
Коллеги, получается. Слушайте, а кому вы преподаёте? В смысле возраста. И насколько обучение у вас добровольное? Это школа/университет или какие-то кружки или курсы? Аудитория сильно влияет на представление о том, как и что преподавать.
писать программы не вводя понятие типов
Ну как тот чувак, что говорил прозой. То что килограммы с метрами не складывают - учитель физики смог обьяснить же. Программистам, если они физику прогуляли, можно показать картину 'Девочка и жабоскрипт'. С комментариями, конечно.
Стажировки и доп.обучение по месту работы, плюс несколько лет преподавания на курсах (на курсах уже не работаю). Аудитория взрослая. Причем на курсах - совершенно различный стартовый уровень. Обучение через разработку небольших игровых приложений: крестики-нолики, шашки и т.д. Плюс разноплановые интересные задачи.
Я не говорю про полное отстутствие понимания типов. А про явное их указание в том же Паскале.
Ну и к тому, что можно и что нельзя сделать на Delphi/Pacal. Решил я тут как-то озадачиться написанием своего рантайма для JS на основе движка V-8. Начал искать концы - с чего начать и т.д. Оказалось ни в чем кроме Visual Studio это добро не собирается. Решил я посмотреть в сторону разработки VST-плагинов. Тут тоже ни о каких Delphi / C++ Builder - тоже речи идти не может. В основном библиотеки для разработки и фреймворки для этого заточены под использование Visual Studio. Подавляющее большинство мануалов - то же. Как бы выбор очевиден.
Я понимаю, что в плане удобства использования и набрасывания компонент на форму у Delphi / C++ Builder в свое время конкурентов не было. Но ни одна нетривиальная задача не сводится исключительно к набрасыванию компонент на форму. А когда начинается реальная большая работа с кодом: удобный автокомплит, рефакторинг, поиск в тысячах файлов, переход от файла к файлу и т.д, то и выясняется, что эти вещи, к которым так привык, у Delphi остались на уровне 15 - 20 летней давности. А последняя версия Free Pascal, который якобы интенсивно развивается, вышла 20 мая 2021 года - 4 года назад "FPC version 3.2.2 has been released!" И после этой даты там только 2 новости. Такая себе активность...
И поэтому ни с какой стороны сейчас я не могу рекомендовать начинать изучение программирования, используя Pascal.
Free Pascal каждый месяц выпускает версию в транк, вы смотрите не понятно что.
https://www.freepascal.org/ - Не знаю, вот источник. Википедия тоже подтверждает это: последняя стабильная версия - "3.2.2 / May 20, 2021; 4 years ago "
Стажировки и доп.обучение по месту работы, плюс несколько лет преподавания на курсах (на курсах уже не работаю). Аудитория взрослая. Причем на курсах - совершенно различный стартовый уровень. Обучение через разработку небольших игровых приложений: крестики-нолики, шашки и т.д. Плюс разноплановые интересные задачи.
Так если уровень разный тем более в начале важно к одному знаменателю привести всех. А раз у кого-то опыт есть, то это отличный случай сказать "Вот, Виктор Петрович, вы на плюсах умеете программировать, эта вещь там реализована так, а вот тут -- эдак; а вы, Валерий Палыч, можете заметить, что там и тут такие-то вещи реализованы одинаково. Что, кстати, это значит, как вам кажется?". Отличная же почва для обсуждения и погружения в какие-то важные нюансы.
Вообще считаю, что крайне важна привязка к каким-то реальным задачам, понимание того, какие конкретно задачи можно решать теперь быстрее, удобнее или в принципе решать.
Я не говорю про полное отстутствие понимания типов. А про явное их указание в том же Паскале.
Так мы в том же питоне пишем, прости господи,
a = float(input())
b = float(input())
print(a + b)Чем это принципиально отличается от явного указания в паскале? Ну или там в плюсах каких-нибудь. Так и так приходится типы указывать чтобы что-то написать.
Но когда ты сам, своими ручками присваиваешь переменной какой-то тип, то потом более чётко понимаешь, почему что-то пошло не так, когда оно пошло. А когда язык позволяет в львиной доле случаев махнуть рукой в надежде, что оно там само как-то приведётся к нужному виду, то это расхолаживает и прививает дурные привычки. Не даёт это понимание процессов, лежащих за упрощённым синтаксисом.
Это, знаете, сродни использованию встроенных функций типа max() в питоне. Вот просишь людей решить какую-нибудь простую задачу типа "из трёх чисел найдите максимальное" и большинство людей не задумываясь напишет max(a, b, c). Оно-то, конечно, работает, но оказывается, что используя условный оператор как минимум половина с первого раза верно задачу не решит. И, казалось бы, бог с ним, но в какой-то момент объекты усложняются, появляются, например, классы и тут оказывается, что для них не то что поиск максимального, простое сравнение не работает само по себе. И вот встаёт перед нами задача сортировки объектов класса, скажем, а человек из трёх чисел большее найти не может без ошибок. Разве это хорошо?
Подводя итог: интересные и полезные задачи важны и нужны, тут я полностью согласен. Но не уверен, что питон или яваскрипт дают такое уж большое преимущество в обучении.
Отчасти могу согласиться с сомнительной актуальностью паскаля, но в предыдущем сообщении писал уже, что с тем же успехом можно использовать в качестве первого языка С++ или C#. Уж в их-то акутальности вряд ли кто-то станет сомневаться, а методической пользы больше, как по мне.
Для Delphi есть врапперы движка V8. Есть также JavaScript-движки, написанные на Паскале. Есть врапперы для альтернативных движков JavaScript.
Что изучавший Паскаль будет делать после окончания его изучения? Где он сможет применить на практике полученные знания? На пет-проектах? А что потом? Сразу переучиваться на другой язык? А почему в таком случае не начать с этого другого языка и не изучить все необходимые концепции на нем?
А почему учатся гонять на картингах, а не садятся сразу на Ф-1?
А почему сначала ходят в походы - "единички", а не лезут на Эверест?
Все верно. Начинать надо с Python или JS - просто, наглядно, легко запустить, потом легко применить где-нибудь еще. И лучше всего с графических задач, поскольку современные дети никогда не видели терминала и в идею текстовой консоли вообще не врубаются.
Питон и JS - это как раз больше про терминал и проблемы с запуском. Да, JS можно запустить "в каждом браузере", только это не удобно и близко не интересно. А Питон вообще без среды работать не будет или без костылей типа pyinstaller. При чем даже с pyinstaller вообще не 100%, что всё запустится у друга.
В Паскале (Delphi) ты запустил среду и у тебя уже открыт проект и форма. Это можно запустить одним кликом и один единственный ехе уже есть в папке и его можно передать. Запустится это вообще на любой винде. А переключив платформу и на Андроид запустится.
Так намного проще вызвать интерес у школьников. Пусть себе кидают компоненты на форму и смотрят, что получится. Всё наглядно и не надо ничего вообще гуглить, ставить через ту же консоль.
А Питон вообще без среды работать не будет
В Паскале (Delphi) ты запустил среду и у тебя уже открыт проект и форма
Я запутался ;)
Так намного проще вызвать интерес у школьников.
Не вызвало. Спрашивал у детей, что там у вас по информатике. "Да, какую то фигню не дельфях делали." 20 лет назад программирование мышкой давало вау эффект. А сейчас есть scratch, тоже можно подвигать обьекты.
У школьников дофига школьных задач, и ни одна из них не решается с помощью программирования. Программирование - один из предметов, который сдать и забыть. Вот в чем дело.
А в JS можно подключить графическую библиотеку (например p5) и рисовать картинки. Это интересней, чем формы.
От таких статей и комментариев душа радуется и на сердце тепло. О, я прямо в философию ударился на ночь глядя.
Я поддерживаю на ВСЕ 100%. Я не знаю зачем (особенно на кружках и т.д.) детей 10-ти летнего возраста (+/-) садят за Python. Не хочу обидеть автора Python, но синтаксис его весьма не привычен для начального изучения (это мое личное мнение, может мне так просто кажется).
Спасибо автору за статью.
детей 10-ти летнего возраста зря пихают в программирование на любом языке.
Конечно. Надо начинать с 7. И точно изучать основы алгоритмизации раньше арифметики.
Нас в большом количестве окружают люди, которых дома и в школе не научили упорядочивать собственные действия, это ужасно.
Солидарен. И за основы алгоритмизации после блок-схем, которые ненавидел, гораздо приятнее стало взяться за настоящий инструмент, который в то время был Бейсик и чуть позже Паскаль. В голове сразу всё сложилось как надо - тут не надо чертить, тут надо компьютеру команды выдавать. "Программа делает то, что вы ей скажете, а не то, что вы хотите" ) Логика же
Интересно, согласен со многим. Я когда-то ходил в Воскресную школу в РГУ, ещё в 2003 году, и был очень восхищен Pascal ABC, и разработкой Михалкович Станислава Станиславовича, и Абрамяна Михаила Эдуардовича, и их обучающей системой.
А вот с Kotlin даже не знаю, наделать неоднозначностей в нем можно по-моему проще чем в Pascal, Java, C# вместе взятых.
Да и эффективность под вопросом, в сравнении с Java, особенно если посмотреть декомпиллированный код. Все эти "вкусности", внутренни часто решаются через рефлексию, там где по сути не могло б не быть. Я с Kotlin работал крайне мало, и даже тогда меня застали в расплох методы, описываемые вне класса, а в одном месте я получил ошибку, которую я смог найти только после декомпиляции байткода, т.к. она проявлялась в рантайме в сгенерированом кодое, с рефлексией.
Порой "мощность" и "лёгкость" в совокупности, может создавать иллюзию, когда думая, немного в другом русле, код можно написать короче и эффективнее. Особенно это можно увидеть когда нужно переписать какой-то существующий код к примеру с Kotlin на Java или с Python на C#, оказывается что некоторые задачи решаются в лоб "по старинке", проще, короче, чем были решены в изначальном коде.
Да и эффективность под вопросом, в сравнении с Java, особенно если посмотреть декомпиллированный код.
Разве что под вопросом, потому что сравнивать надо на реальных бенчмарках, а сам байт-код мало что дает, поскольку он сильно оптимизируется джитом.
Все эти "вкусности", внутренни часто решаются через рефлексию, там где по сути не могло б не быть.
Можно пример такого поведения? В Котлине наоборот есть вещи, которые недоступны в Java: value классы с одним полем, синтаксический инлайнинг, reified типовые параметры. Скоро еще появится более продвинутая compile time reflection.
Я с Kotlin работал крайне мало, и даже тогда меня застали в расплох методы, описываемые вне класса
Субъективное мнение. Вас застали врасплох, а кого-то, наоборот, порадовали.
а в одном месте я получил ошибку, которую я смог найти только после декомпиляции байткода, т.к. она проявлялась в рантайме в сгенерированом кодое, с рефлексией.
Как давно это было и опять-таки не помешал пример этой ошибки.
Вспомнил я историю, связанную с изучением программирования.
Преподавал я лет 9 назад на курсах Node.js. Народ разный там встречался, уровень тоже разный, но много начинающих. И вот в одном из потоков учились двое друзей - один был достатончо продвинут - все примеры на своем ноутбуке делал прямо в консоли, безо всякой IDE. А второй - второй почти всегда приходил малость выпивши. Но я его не стал выгонять, так как он был не один, ну и никогда проводить занятия не мешал. Ну такое вот сыто-выпимши. Не думал я, что из него что-то получится.
Ну и где-то месяца через 4 встречаю его в метро, подбегает ко мне - трезвый, зоровается и говорит: Огромное Вам спасибо! Взяли меня на работу программистом...
Ради интереса поискал Python на ХХ - 8655 вакансий. Pascal - 250. Итого разница примерно в 35 раз. Это не учитывая прикладные инструменты Python...


Почему Pascal лучше для обучения программированию, чем Python