LINUX.ORG.RU

ЛОР, помоги выбрать ЯП для обучения

 , , , ,


1

3

Часто слышу просьбу научить программированию. Хотя пока я этим не занимаюсь, мне стало интересно, какой ЯП выбрать для введения в программирование.

Вот к каким мыслям я пришёл:

Язык должен наиболее чисто демонстрировать самые основы написания кода.

Не Си и не современные коммерческие языки (Java, C#, Go). Си, хотя примитивный в основе, усложнён из-за окружения, в котором используется. Современные коммерческие языки были созданы для решения проблем индустрии. Проблема общая: я хочу преподавать материал по мере нарастания сложности. Если в языке неизбежно приходится использовать классы или printf, то это затруднит объяснение (не хотелось бы слишком часто говорить «потом узнаешь для чего это нужно»), напугает студента (ему придётся писать код, используя возможности, которые он плохо понимает), создаст неправильное восприятие основ (как будто printf — это какая-то важная часть компьютера или ОС).

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

Языки, между которыми я выбираю: Pascal и Python.

Pascal устарел и денег не принесёт (обидно), но это и не является основной целью. Целью является программирование, а не современное окружение.

В частности, я не собираюсь задрачивать студента на Delphi или любой «продвинутый» диалект языка. Это противоречит цели. Я рассчитываю на то, что после должной тренировки “bare bones” нужно перейти на современный язык и это будет легко.

Важно упомянуть, что спека языка Oberon (Виртовский язык, тот же Паскаль, только упрощённый и доработанный) составляет 17 страниц.

Питон мне сложнее оценить, потому что я избегал работы с ним.

Если ограничиться императивным подмножеством, без ассоциативных массивов, классов и мета-классов, list comprehensions, HOF, исключений, то выглядит как альтернатива Паскалю. Хотя меня беспокоит динамическая типизация. Типы — очень важная вещь, хотелось бы чтобы язык помог это донести, а не быть типа «ну да, это важно, но ты забей».

Это все мои мысли.

Что касается практики, то я имел несчастье наблюдать как человек впервые знакомился с программированием, изучая Java на javarush. На это было больно смотреть.

Edit: дальнейшие пояснения по теме:

  • Подробнее про то, почему я считаю, что изучение основ и Паскаль хорошо сочетаются: 1
  • Почему не Си и не ассемблер: 1 2
  • Почему Паскаль: 1 2
  • Почему не Питон: 1
  • Целевая аудитория: 1
  • Почему такая размытая аудитория: 1 2
  • Про важность иерархии: 1


Последнее исправление: kaldeon (всего исправлений: 10)
Ответ на: комментарий от rebforce

Естественно. А код, который сам явно не резолвит имя файла перед использованием — говнокод.

Эээ… нет? Потому что это ломает огромную кучу кейсов?

anonymous
()
Ответ на: комментарий от rebforce

Естественно. А код, который сам явно не резолвит имя файла перед использованием — говнокод.

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

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

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

rebforce
()
Ответ на: комментарий от no-such-file

Это ты не понял. В ЛИСПе a = b + c может значит вообще что угодно, в т.ч. например if a then b else c. А в крестах нет,

Это всё очень замечательно, но что делает код A = B + C в С++ вы так и не рассказали. А ведь казалось бы, что может быть проще?

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

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

Короче, завязываю кормить.

rebforce
()
Ответ на: комментарий от no-such-file

Тогда однако некорректно приводить кресты как контрпример.

У вас высказывание, если я правильно понял, Lisp непопулярен/нельзя показывать новичкам, потому как на нём можно наворотить такое, что глаза на лоб полезут. Но тогда популярный язык, в котором можно сделать то же самое, является отличным контрпримером.

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

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

Сократ сказал о сочинениях Гераклита: „Что я понял — прекрасно; чего не понял, наверное, тоже: только, право, для такой книги нужно быть делосским ныряльщиком.“

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

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

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

какие есть «четкие алгоритмы» у функции, которой подставили какую-то чушь?

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

функция ждет относительный путь,

А должна ждать reader, который уже автоматом преобразует путь к файлу (не важно асолютный или относительный) в поток символов.

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

преобразовать относительный в абмолютный вы можете только зная базовую диру. относительно которой брался относительный. а она такой диры не знает. и что ей делать-то?

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

и лопаты с землекопами будут разными типами и вы не подставите одно вместо другого.

вообще 99 процентов сущностей в программе несовместмы друг с другом. и это контролируется их типами. а когда типов нет - получается куча мала.

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

функция ждет относительный путь, ей дают абсолютный.

Ну так она должна проверять, какой это путь. Валидация входящих данных, не слышал, не? Типизация здесь не поможет, даже если, как в реболе/реде, типов нагородить на все случаи жизни. Ничто не мешает ./lol передать вместо /var/lol и в какой-нибудь конструктор. А если мешает, то что мешает ту же валидацию сделать в той функции, которой эти данные нужны? Без лишних сущностей вроде нового типа на каждый чих.

функция ждет градусы цельсия, ей дают фаренгейты и наоборот.

Это вообще никак не верифицируется, разве что предельные диапазоны задать.

какие есть «четкие алгоритмы» у функции, которой подставили какую-то чушь?

Ты так и не ответил, кто же туда эту чушь будет подставлять, если пользовательские данные уже отвалидированы и оттранслированы в нужный формат.

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

Это вообще никак не верифицируется, разве что предельные диапазоны задать.

да ты чо!!! просто это описывается как разные типы.

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

если есть конструктор фаренгейтов из цельсиев и он верно написан - он сделает нужное преобразование. если не написан - просто будет ошибка.

в твоем же мире - все пройдет гладко. и будет заведомо ошибкой.

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

Это ты рассуждаешь о своих скриптах на 10 строк, которые разрабатываются только тобой, и имеют малую историю.

У каждого проекта свои потребности, свои ограничения. Для простых скриптов никто не берет сложные языки.

Типы это дополнение к документации, чем лучше система типов, тем лучше они описывают код. И тем больше компилятор добавляет проверок, и оберегает программиста от ошибок.

Код меняется, меняется документация, старый код может стать неправильным, новый может писаться по старой документации.

Еще типы это огромный буст для инструментов, и IDE, например автокомплит сразу становится адекватным и точным.

Вот видео с примером функции на C и Rust. На С определение выглядит простым, но не раскрывает важных принципов ее работы, и не защищает от ошибок.

https://youtu.be/WiPp9YEBV0Q?t=537

Про твои 1000 строк которые заменят миллион смешно читать, жду переписывание хрома или ядра. Можно заменить только отказавшись от всего функционала. Основная логика в чистом виде вполне может занимать очень и очень большой объем, который никак от более простой склейки строк из коробки не уменьшить.

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

Нет, вообще не так. У меня есть число 20. Я его передаю в конструктор фаренгейтов, думая, что это фаренгейты. А это цельсии. Эту ситуацию вообще никак не отловить. Горожением типов ты просто передвигаешь место возникновения ошибки: не при передаче в функцию, а при передаче в конструктор.

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

И что мне мешает передать цельсии в конструктор для фаренгейта?

Компилятор

// Цельсий
struct C { double value; };
// Фаренгейт
struct F { double value; };

C operator ""_C(long double);
F operator ""_F(long double);

// Цельсии в фаренгейты
F c2f(C x) {
    return { x.value * 123 };
}

int main() {
    // Температура в фаренгетах
    auto temp = 10.0_F;
    auto temp_in_f = c2f(temp); // gcc error: could not convert 'temp' from 'F' to 'C'
}

MOPKOBKA ★★★★★
()
Последнее исправление: MOPKOBKA (всего исправлений: 5)
Ответ на: комментарий от ugoday
#define A "ТВОЮ"
#define = "МАМКУ"
#define B "ШАТАЛИ"
#define + "ВСЕМ"
#define C "ПОДЪЕЗДОМ"

ОЛОЛО НЕВОЗМОЖНО ПОНЯТЬ ЧТО ВЫРАЖЕНИЕ ЗНАЧИТ НА C.

Давайте как-то без упорина уже?

anonymous
()
Ответ на: комментарий от rebforce

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

  • Multicall binary. Открывал /bin/mkdir, отрезолвил в /bin/busybox.

  • TOCTOU race. Открывал симлинк, в процессе его атомарно заменили через move, получил гонку на пустом месте.

anonymous
()
Ответ на: комментарий от MOPKOBKA

Минуточку, а юзер их так же будет вводить? 10.0_F и 10.0_C? Если нет и на входе только сами числа, то придётся с какой-то точки следить, чтобы они записались в правильную структуру. А если да, то что мешает гонять их в виде строк и парсить только там, где это нужно для вычислений, однозначно зная, что это за градусы?

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

Тогда все становится ещё более непонятно: зачем резолвить локальные пути? Что это дает, кроме траты времени на обход дерева?

anonymous
()
Ответ на: комментарий от rebforce

Минуточку, а юзер их так же будет вводить? 10.0_F и 10.0_C?

Цельсии и фаренгейты да.

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

Можно их в каком угодно виде передавать. Я не особо понял что это дает. Ты хочешь сразу с буквой C/F, что бы сохранить тип? Можно так, и проверять при входе в функцию. Или сделать num = unpackOnlyC().

Или даже сделать extension что бы перед аргументом функции можно было записать C, F и это через рефлексию проверяет аргумент. Можно назвать такие штуки типами.

Преимущество ЦПП тут: Это все понимает IDE, это проверяется статически и при изменении кода тебе укажут на места где это может сломаться, все преобразования выбрасываются компилятором потому что они существуют только в CompileTime.

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

Бывают ситуации, когда у модулей, конфигов и прочего надо поменять вложенность. А они друг на друга ссылаются через ../a/b/c какие-нибудь. Добавить к этому разницу между $PWD и непосредственно каталогом с исполняемым скриптом — и вот уже проще получить корневой каталог в абсолютном виде и резолвить относительно него, чем уповать на какие-то внешние механизмы.

rebforce
()
Ответ на: комментарий от monk

Покажите ругань компилятора на то, что футы в одной переменной и метры в другой обозначили типом Integer?

А не надо так делать,надо производные типы от int создавать. Можно еще и с ограничениями диапазона допустимых значений - Ада такое умеет.

Scheme или Python лучше.

С Scheme дела не имел,а у Питона еще большая беда с типами - он очень уж вольно с ними обращается.

watchcat382
()
Ответ на: комментарий от alysnix

а она такой диры не знает. и что ей делать-то?

У процесса есть рабочая директория на этот случай. Вот её и использовать.

в типизированном языке вы просто пишете два разных типа - путь абсолютный и относительный

Вы придумали отличный костыль, чтобы подпереть плохую архитектуру. Поздравляю.

P.S. Это не в рамках срача строгая/слабая типизація. Просто конкретно ваш пример захотелось обсудить.

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

у Питона еще большая беда с типами - он очень уж вольно с ними обращается

Например? Большая часть его проблем для меня исходит из динамики, а не из типов. Наоборот для меня у него слишком строгая типизация для маленького скриптового языка.

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

У меня есть число 20. Я его передаю в конструктор фаренгейтов, думая, что это фаренгейты.

Ну с тем же успехом вы можете сказать: „У меня есть число 20, а на самом деле 25, я просто опечатался“. Против лома нет приёма. Зато когда у вас будет результат конструктора фаренгейтов и результат конструктора цельсиев, вас компилятор отругает, если вы захотите сложить их друг с другом.

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

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

Справедливости ради, на DrRacket уйма учебных курсов. Правда с 2010 года ещё пару десятилетий не прошло.

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

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

rebforce
()
Ответ на: комментарий от alysnix

в типизированном языке вы просто пишете два разных типа - путь абсолютный и относительный

А потом надо написать fopen и какой тип ставить? Или делать две версии fopen? Или передавать вариантный тип?

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

когда с ними в сериализованном виде таскать обозначение этой самой размерности

Где это в моем коде? Или ты так типы назвал? Разницу между твоим подходом, и ЦПП я в комментарии описал.

К предоставляемым самим ЯП типам это не имеет никакого отношения

Ну либо в ЯП есть возможность работать с типами на таком уровне, либо нету. Там где нету, придется строчки за числами таскать. И проверки с конвертациями которые не проверяются статически расставлять.

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

Вы, наверное, и русские буквы в именах файлов не используете (потому что однажды в 96-м году под MS DOS’ом кривой скрипт запортил данные, потому как не ожидал, что кроме латиницы что-то ещё бывает).

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

Бывают ситуации, когда у модулей, конфигов и прочего надо поменять вложенность. А они друг на друга ссылаются через ../a/b/c какие-нибудь. Добавить к этому разницу между $PWD и непосредственно каталогом с исполняемым скриптом — и вот уже проще получить корневой каталог в абсолютном виде и резолвить относительно него, чем уповать на какие-то внешние механизмы.

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

anonymous
()
Ответ на: комментарий от monk

По-моему в zig какой-то такой упорин и есть.

anonymous
()
Ответ на: комментарий от ugoday

А зачем мне их даже пытаться складывать друг с другом? Даже если не отругает.

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

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

А зачем мне их даже пытаться складывать друг с другом?

Совершенно незачем. И именно по этому и нужна проверка.

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

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

Это точно будет медленнее если не применять особые ухищрения и не создавать экстеншены на С. Это точно не будет подхватываться стат.анализаторами и IDE если не писать к ним свои плагины для каждой библиотеки.

Я еще считаю что это выйдет длиннее.

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

Но зачем, опять же?

Чтобы написав программу получать именно те результаты которые задумывались вами,а не авторами какого-нибудь монстра типа QT или GTK. Попробуйте например на нем сделать интерфейс в точности такой как нужно вам,а не как получилось за счет забитых где-то глубоко умолчаний. Например чтобы к нужному полю ввода в форме можно было перейти кратчайшим путем используя курсорные стрелки,а не прощелкивать все подряд поля tab-ом пока до нужного не доберетесь. Оно таки возможно,как минимум на Си,но мата сквозь зубы будет много. Как с этим на других языках из которых возможно использование этих библиотек - не знаю. После однократного погружения в недра Gtk лет двадцать назад - больше желания связываться с ними не возникало,предпочитаю что попроще.

write less code to get the same things done.

Так вот в том-то и дело что ни разу не same (как было надо вам),а как соизволили написать те кто писал нижележащие абстракции,которые делали их для каких-то своих задач как им было удобно.

watchcat382
()
Ответ на: комментарий от ugoday

если я правильно понял, Lisp непопулярен/нельзя показывать новичкам, потому как на нём можно наворотить такое, что глаза на лоб полезут

Ты неправильно понял. Чувак сморозил чушь про «ЛИСП простой как три рубля», выучил 2 правила = выучил ЛИСП. Это не так. В контексте обучения это тоже имеет свои последствия, но не в этом была суть возражения.

no-such-file ★★★★★
()
Ответ на: комментарий от ugoday

Вы придумали отличный костыль, чтобы подпереть плохую архитектуру. Поздравляю.

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

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

тоже мне, архитектор там завелся. архитектура тут вообще не причем.

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

Носитесь с этими типами, как с писаной торбой.

И правильно носимся. Потому что это позволяет писать программы с предсказуемым поведением.

об этом должен заботиться тот код, который принимает только целое/дробное число.

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

watchcat382
()
Ответ на: комментарий от alysnix

потому являются разными типами по определению.

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

аналогично часы и минуты.

Три часа плюс пятнадцать минут будет три часа пятнадцать минут. Привет.

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

Удивительно, как половина отписавшихся в этом треде не пишет из собственноручно написанного браузера на собственноручно написанной ОС на собственноручно изготовленном железе собственноручно разработанной архитектуры. Ведь там абсолютно всё будет сделано так, как нужно именно вам и только вам!

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

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

Нет, вообще не так. У меня есть число 20. Я его передаю в конструктор фаренгейтов, думая, что это фаренгейты. А это цельсии.

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

alysnix ★★★
()
Ответ на: комментарий от no-such-file

Ты неправильно понял. Чувак сморозил чушь про «ЛИСП простой как три рубля», выучил 2 правила = выучил ЛИСП.

Урежем осетра до «Необходимое и достаточное для обучения программированию подмножество lisp’а можно объяснить за 15 минут» и сойдёмся на этом?

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

ugoday ★★★★★
()
Ограничение на отправку комментариев: