Comments 309
Очень сложно обьяснить человеку, не знакомому с понятием "мебель" значение слова "табуретка": ведь это не коврик, не стог сена, даже не лошадиное седло.
Можно показать "в натуре" - но с компьютерами это сложнее.
Хорошо, когда пришел в IT из электроники и сразу в ассемблер: регистр и ячейка памяти уже имеют вполне определенный физический смысл, 16 или 32 бит буквально представляешь глазами, и понимаешь как именно может выглядеть "возврат значения".
А когда всё это - волшебные заклинания, которые нужно просто запомнить - ну, сложновато, конечно.
Очень сложно обьяснить человеку, не знакомому с понятием "мебель" значение слова "табуретка": ведь это не коврик, не стог сена, даже не лошадиное седло.
Не так и сложно, если уметь в хорошие абстракции, и понимать тот уровень и понятийный аппарат которым владеет потенциальный читатель. Собственно в этом и заключается хороший преподавательский талант. Главное не уходить преждевременно в глубокие детали, пока не объяснил "на пальцах" саму суть явления.
"Табуретка? Представь что у тебя есть обычный пенек, кусок ствола дерева на которым ты сидел во дворе, но ты хочешь сделать легким для удобной переноски. Для этого берешь тонкий спил, вместо высокого - то на чем будешь сидеть и ставишь его на палки в качестве ножек, чтобы он был нужной тебе высоты."
Ту же упомянутую "длину" переменных можно объяснить через органайзер с ячейками - если у тебя в пенале 16 ячеек размерами под твои предметы, а тебе нужно класть в него больше, значит ты выбрал не верный пенал, нужно взять большего размера. Почему сразу не взять максимально большой? А потому что они места больше занимают, это очевидно же!
А как именно в электронике ты представляешь глазами 16 бит, например? Для меня это скорее математика, чем физика
Странный вопрос. В простейшем виде, как 16 D-триггеров. Примерно, таких:

В частности, если речь о DRAM, то 16 ячеек:

Тут бы старший байт от младшего научиться отличать..
У старшего вес в числе больше. Всё как у людей.
Для этого сначала надо разобраться c big-endian и little-endian. А если речь уже о int32 или int64, то еще, возможно, и с mixed-endian
big-endian и little-endian
А кто как их запомнил? Я как "большое и маленькое удобство для глаз".
Большое или маленькое изменение произойдёт, если мы изменим первый байт? Ещё помогает то, что в названиях платформ (mips64el) используют "перевёрнутый" суффикс "el" (endian little).
Исторически это от больших и маленьких компьютеров. Большие компьютеры изначально оперировали целыми словами, поэтому у них и биты в слове расположены последовательно, а маленькие компьютеры шли от байтов, поэтому байты запросто оказались переставленными.
Не уверен, что это подходит в качестве мнемонического правила, но это реальный смысл терминов.
Сам термин - это вообще спор от "с какого конца лучше разбивать яйцо - с маленького или большого".
а маленькие компьютеры шли от байтов, поэтому байты запросто оказались переставленными.
Это ничего, что "маленькие компьютеры" начались с моделей типа PDP-1, в которых никакого "шли от байтов" не было, байтовая S/360 была BE, а PDP-11, которая первая известная LE, всяко больше PDP-1 и позже неё аж на 12 лет?
но это реальный смысл терминов.
В IEN137 ничего похожего нет, поэтому прошу уточнить, откуда у вас такие сведения.
В S/360 впервые появились байты (как минимальная единица адресации памяти, но! не выборки из памяти и не обработки данных в процессоре), и в связи с этим вообще стало возможным ставить вопрос о каком-либо *-endian. Очевидно, что пока байтов нет, то и *-endian нет. Но по своей области применения и части особенностей архитектуры это был классический большой компьютер того времени, оперирующий достаточно длинными для представления чисел 32-разрядными словами. Как и любая большая машина (big iron), он распечатывал слова с числами в дампе памяти в естественном порядке разрядов, т.е., если рассматривать их как набор байтов, то big-endian, вот и всё.
Когда появились мини-ЭВМ, где байты уже стали не только единицей адресации, но и единицей обработки данных в процессоре, то стало в принципе всё равно, в каком порядке их упорядочивать при представлении слов, и появились первые little-endian машины, такие как PDP-11 (хотя практический смысл little-endian кодирования от меня ускользает). PDP-11 в момент своего создания считалась маленьким компьютером (мини-ЭВМ), вот и назвали little. На момент 1980 года, когда был написан IEN137, все машины класса big iron были big-endian, а часть машин класса mini и micro была little-endian. Всё очень логично.
Конечно, существуют и big-endian микропроцессоры тоже, поскольку разница касается только восприятия человеком и не имеет принципиального технического характера. О чём написано и в IEN137.
Единственная значимая в техническом смысле особенность little-endian по сравнению с big-endian состоит в том, что можно начальную часть длинного числа прочитать как короткое число, и всё сойдётся, если старшие биты были нулевые. Я бы это считал скорее недостатком, маскирующим ошибки описания данных. А всё остальное касается только того, инкрементировать или декрементировать счётчик байтов при обработке числа (что однофигственно) и насколько удобно человеку читать дамп.
Очевидно, что пока байтов нет, то и *-endian нет.
Грубо неверно. Смотрим, например, в каталоге форматов плавающей точки. Первым же пунктом формат IBM 704, 709 и прочих. Или HP3000 сразу следующим. Двойная точность представлена в них всех двумя словами. В каком именно порядке в памяти хранятся эти два слова, где старшая часть мантиссы, а где младшая?
А если нужно самому реализовывать длинную арифметику, в каком порядке будут храниться лимбы, если, например, один лимб это слово 18-битной машины?
На момент 1980 года, когда был написан IEN137, все машины класса big iron были big-endian, а часть машин класса mini и micro была little-endian. Всё очень логично.
Из этого никак не следует, что выбор термина big-endian связан с "большими машинами". Это могло точно так же появиться чисто случайно. В тексте документа связи нет. Именно поэтому мой вопрос - какие ваши доказательства (™), какие ещё источники утверждают, что это не случайно получилось, а намеренно.
А всё остальное касается только того, инкрементировать или декрементировать счётчик байтов при обработке числа (что однофигственно)
Складываем/вычитаем два длинных числа, они могут быть неодинаковой длины. Если хранить лимбы в LE (независимо от того, какой порядок байтов одного лимба), то индекс одинаков: сложил по индексу 0, потом по индексу 1, потом 2... А если хранить в BE, то нужно держать два разных индекса. Это, конечно, мелочь, но это именно что технический аспект.
В остальном согласен, что на ≈95% разница для человека. (Остаток - типа создания ключей для сортировки - в пользу BE. Возможно, ещё что-то придёт в голову, допишу тогда.)
Расположение слов в вещественных числах и элементов массивов переменой длины всё же обычно не принято отождествлять с big- и little-endian. Тем более что в некоторых архитектурах (типа той же S/360) внутренний формат этих слов неодинаков.
Из этого никак не следует, что выбор термина big-endian связан с "большими машинами". Это могло точно так же появиться чисто случайно.
Так, чтобы кто-то написал: "я придумал термин big-endian в честь big iron", я не видел. Но во многих текстах эти понятия увязываются между собой, и выглядит это весьма логично.
В интел little endian.
Ну а дальше всё логично.
Почему странный?)) Не все же на Хабре электронщики)) Но в целом я понял - вам было от чего отталкиваться.
Так и я не электронщик. Я программист. Просто я учился программированию начиная с емкостей, индуктивностей, pn-переходов и полевого эффекта. И я даже плохо себе представляю, как можно стать IT профессионалом, не имея понятия об этой базе. Особенности DRAM, PCIe, CPU и т.п. без этого будут выглядеть как набор догм. Мне лично комфортней и проще, когда я понимаю, а не когда зубрю. Одно дело зубрить, что это так, а совсем другое - понимать, почему и зачем.
Просто я учился программированию начиная с емкостей, индуктивностей, pn-переходов и полевого эффекта. И я даже плохо себе представляю, как можно стать IT профессионалом, не имея понятия об этой базе.
Точно так же, как можно стать IT-профессионалом, не имея понятия о теории типов, матлоге и теории категорий, и не зная, при каких условиях на 𝒞 категория ℰ^𝒞 — топос, если ℰ — топос. Ну, просто это всё на практике не нужно, кроме очень узких областей.
Точно так же, как можно стать IT-профессионалом, не имея понятия о теории типов, матлоге и теории категорий
Вы бы пояснили всё же Вашу аналогию примером. Я действительно не понимаю, почему перечисленное Вами является необходимым для глубокого понимания того, как работает компьютер.
Ну так вы согласны, что это не является необходимым — здесь мы сходимся, и здесь, выходит, пояснять нечего. А аналогия моя в том, что знание ёмкостей, индуктивностей, pn-переходов и полевого эффекта тоже не является необходимым для того, чтобы быть IT-профессионалом. Перечисленные мной вещи — это и есть пример.
Я код писать стал сильно до того, как изучил в вузе зонную теорию проводимости и pn-переходы. Это знание на то, как я пишу код, не повлияло вообще никак. Даже базовые ёмкости и индуктивности у меня тоже были классе в десятом, наверное — сильно после того, как я начал программировать, и на мои навыки написания кода они не повлияли тоже никак. При этом некоторые (очень базовые, впрочем) аспекты матлога и теории типов я таки ощущаю полезными даже в обычных прикладных задачах.
Конечно, возможно, вы хардкорный железячник, и добрая часть вашей работы сводится к непосредственно железу, но не все IT-профессионалы — хардкорные железячники (точно так же, как не все IT-профессионалы — специалисты по теории типов и формальным методам доказательств).
Ну так вы согласны, что это не является необходимым
Как я могу быть согласен с утверждением которое не понял? Вы сначала объясните, почему перечисленное Вами является необходимым для глубокого понимания того, как работает компьютер.
Я код писать стал сильно до того, как изучил в вузе зонную теорию проводимости и pn-переходы. Это знание на то, как я пишу код, не повлияло вообще никак.
Во-первых, "код писать стал" и "стал IT профессионалом" - несколько разные вещи.
Во-вторых, видимо, Вам удобней зубрить, чем понимать. Я сталкиваюсь с такими людьми регулярно. Но ещё ни разу я не встречал профессионального программиста, предпочитающего зубрить, а не понимать, почему и зачем.
Например, можно зазубрить, что доступ к кеш памяти быстрее, чем к основной памяти, но если не понимать почему это так, то будет неэффективный код, когда столкнётесь с архитектурой, где это не так. А понимание работы кеш памяти важно даже при программировании на Python.
Вы сначала объясните, почему перечисленное Вами является необходимым
Так оно не является необходимым, в том-то и суть.
для глубокого понимания того, как работает компьютер.
Вы изначально говорили про IT-профессионалов в целом. Глубокое понимание, как работает компьютер (для которого пишутся программы), необходимо настолько же, как глубокое понимание, как работает математическая логика (на основе которой пишутся программы) — то есть, совсем не необходимо.
Можно успешно решать бизнес-задачи, быть полезным в обществе и считаться IT-профессионалом без этих знаний.
Например, можно зазубрить, что доступ к кеш памяти быстрее, чем к основной памяти, но если не понимать почему это так
А задержки доступа к L1/L2/L3/RAM (и размеры кэшей, и особенности TLB) для конкретного процессора сможете вывести из первых принципов и pn-переходов, или всё равно придётся зубрить? А от их конкретных значений и соотношений зависит, какой код будет оптимальнее для данной конкретной машины (поэтому, например, ATLAS при компиляции под железо просто проверяет кучу разных комбинаций размеров кернелов и выбирает наиболее подходящее).
Как далеко от понимания pn-переходов до конкретных протоколов синхронизации кэшей и методов избегания false sharing'а между ядрами? Или, по факту, всё равно надо зубрить что-то в духе «ядра синхронизируются по кэш-линиям, поэтому независимые атомарные переменные должны лежать в разных кэш-линиях, а лучше — через несколько, чтобы префетчер не портил малину»?
Необходимость vzeroupper
для эффективного кода (возникающую исключительно из-за особенностей работы legacy SSE с AVX-регистрами) сможете вывести из первых принципов и pn-переходов, или тоже придётся зубрить?
то будет неэффективный код, когда столкнётесь с архитектурой, где это не так.
Среди того, чем я профессионально занимался и могу заниматься — пытаюсь писать наиболее эффективный код и пытаюсь обыграть других людей, пытающихся писать наиболее эффективный код, и всё это в игре с нулевой суммой и существенным вознаграждением aka высокочастотный трейдинг (то есть, стимулы писать эффективный код высокие). Не вижу, как знание pn-переходов в этом помогает.
Более того, я не представляю, что должно случиться в мире, чтобы вдруг пришлось писать под архитектуру, где это не так, и как знание pn-переходов помогло бы и в этом случае.
Так оно не является необходимым, в том-то и суть.
Тогда получается, что суть в подмене темы, а следовательно в демагогии.
Глубокое понимание, как работает компьютер (для которого пишутся программы), необходимо настолько же, как глубокое понимание, как работает математическая логика (на основе которой пишутся программы) — то есть, совсем не необходимо.
Вы можете верить в эту догму, но тут, в основном, технические специалисты и в догмы они не верят.
А задержки доступа
А в чем проблема то? Они и выводятся, в том числе, через максимальный коэффициент умножения цифрового ФАПЧ и паразитных индуктивности и емкости схемотехнического решения.
Необходимость
vzeroupper
Для этого нужно понимать, как работает RS-триггер, а следовательно, опять возвращаемся к pn-переходу или полевому эффекту. После чего становится сразу понятно, что выставить reset для любого количества триггеров в разы быстрее, чем загружать логический ноль в них микрокодом.
высокочастотный трейдинг
Например, в FAST процессорах используются решения на FPGA, где без понимания цифровой логики и её базы делать вообще нечего.
Тогда получается, что суть в подмене темы, а следовательно в демагогии.
Нет никакой подмены темы. Это иллюстрирующая аналогия, как я сразу и написал.
Вы можете верить в эту догму, но тут, в основном, технические специалисты и в догмы они не верят.
Утверждение о необходимости не менее догматично (и, я бы даже сказал, строго более догматично, потому что у описываемой с этим утверждением системы большая сложность).
А в чем проблема то? Они и выводятся, в том числе, через максимальный коэффициент умножения цифрового ФАПЧ и паразитных индуктивности и емкости схемотехнического решения.
Отлично! Последний раз я этим занимался на Skylake-X. С интересом посмотрю на вывод задержек доступа к кэшам по упомянутым вами принципам. Продемонстрируете, особенно если проблем, судя по первой процитированной фразе, никаких?
Можно начать с вычисления паразитных индуктивности и ёмкости схемотехнического решения Skylake-X. Мне (и, думаю, вам) этого хватит за глаза.
Для этого нужно понимать, как работает RS-триггер
Нет. Для этого нужно (и достаточно) понимать, что без vzeroupper
процессор предполагает зависимость от старших 128 бит регистра, что является исключительно архитектурным выбором (как, например, является архитектурным выбором сохранять старшие 128 бит ymmN
при работе с xmmN
) и не следует из первых принципов (я тут снова упрощаю — там внутри проца целая стейтмашина, которая у разных микроархитектур разная — наверн, RS-триггеры принципиально разные между поколениями).
выставить reset для любого количества триггеров в разы быстрее, чем загружать логический ноль в них микрокодом.
Зачем загружать микрокодом? Откуда тут это взялось?
Скорость загрузки ноля тут вообще ни при чём, vzeroupper
строго добавляет такты. Дело в разбиении dependency chain в OOO-движке проца.
Как, помогло вам знание pn-переходов, если вы даже не увидели, в чём конкретно проблема и как конкретно она решается?
Например, в FAST процессорах используются решения на FPGA, где без понимания цифровой логики и её базы делать вообще нечего.
В моих задачах FPGA не используется, и?
Зато в моих задачах используется шаблонное метапрограммирование на C++, а это функциональный язык с паттерн-матчингом, а значит, без понимания теорий типов и во что дешугарится паттерн-матчинг там тоже делать нечего. Ведь нечего же? Ведь все программисты на C++, использующие шаблоны, но не знающие типизированное лямбда-исчисление и кодировку Бома-Берардуччи, просто зубрилы и недостойны называться профессионалами?
Нет никакой подмены темы.
Раз Вы не можете не то что доказать, а даже объяснить, какое отношение перечисленное Вами имеет к глубокому понимания того, как работает компьютер, то получается в чистом виде подмена темы, так как обсуждалось именно это.
Утверждение о необходимости не менее догматично
Про то и речь. Я то высказал лишь гипотезу и личное мнение: "я даже плохо себе представляю". А вот Вы пытаетесь утверждать.
Для этого нужно (и достаточно) понимать, что без
vzeroupper
процессор предполагает зависимость от старших 128 бит регистра
Реализация AVX всегда предполагает эту зависимость. А вот то, что сбросить все триггера старших разрядов в множестве регистров сигналом reset в разы быстрее, чем микрокодом, объясняет необходимость этой команды.
vzeroupper
строго добавляет такты
Если в следующей после vzeroupper команде не используются регистры YMM0-YMM15 и ZMM0-ZMM15, то она вообще ни одного такта не занимает. Она лишь позволяет микрокоду, оперирующими с этими регистрами, не обрабатывать 128-ой бит и более старшие. Что и приводит к существенному росту производительности.
В моих задачах FPGA не используется, и?
Остается лишь посочувствовать, так как без обработки FAST протокола на FPGA сейчас в сфере HFT ловить вообще нечего. Ну или Вы занимаетесь только частью работ в реализации HFT, не понимая и не зная целого, что опять таки говорит совсем не в Вашу пользу.
Я в курсе, что с демагогом дискутировать смысла не имеет. Так что до тех пор, пока Вы не укажете, каким образом теория типов связана с пониманием работы компьютера, ответа от меня не увидите.
Как успехи с расчётом паразитных ёмкостей Skylake-X? А то вы как-то замяли эту тему (как и тему про поведение MESI/кешлайнов/префетчера ранее).
Раз Вы не можете не то что доказать, а даже объяснить, какое отношение перечисленное Вами имеет к глубокому понимания того, как работает компьютер, то получается в чистом виде подмена темы
Так что до тех пор, пока Вы не укажете, каким образом теория типов связана с пониманием работы компьютера, ответа от меня не увидите.
Мой тезис в том, что перечисленное изначально вами не является необходимым для того, чтобы быть IT-профессионалом. Соответственно, моя иллюстрирующая аналогия наглядно показывает вам на других примерах, что не обязательно разбираться в фундаменте тех или иных аспектов профессии, чтобы быть продуктивным IT-профессионалом.
Я не понимаю, почему вы систематически от меня требуете показать вам, что приведённые мной вещи необходимы для понимания работы компьютера, если я утверждаю ровно обратное. Как у вас устроена логика (не RS-триггераня, а обычная, формальная)?
так как обсуждалось именно это.
И снова нет, так как вы написали
И я даже плохо себе представляю, как можно стать IT профессионалом, не имея понятия об этой базе.
Если бы вы написали «как можно иметь глубокое понимание работы компьютера», то я бы с вами не спорил.
Правда, если бы вы после этого или рядом написали «без глубокого понимания работы компьютера нельзя стать IT профессионалом», то я бы с вами снова спорил, потому что это не так. А у вас, похоже, эти две вещи отождествляются, потому что вы с большой лёгкостью их регулярно подменяете.
А вот Вы пытаетесь утверждать.
Можете отсыпать «видимо» и «кажется» в мои фразы по вашему усмотрению. Я не вижу смысла в этих словах, так как на высказывание универсальных законов социума мы с вами претендуем в равной степени.
Реализация AVX всегда предполагает эту зависимость.
Поэтому я использовал слово «архитектурное решение», а не «микроархитектурное решение». Но нет никаких фундаментальных законов природы, по которым какой-нибудь AVX-штрих не смог бы избежать этой зависимости. И эти причины вы не сможете вывести из первых принципов вообще никак.
А вот то, что сбросить все триггера старших разрядов в множестве регистров сигналом reset в разы быстрее, чем микрокодом, объясняет необходимость этой команды.
Микрокод тут вообще ни при чём, он никак не делает эту команду необходимой или не-необходимой. Эта команда просто разрывает dependency chain (что я указал в правке предыдущего комментария) на некоторых микроархитектурах, что позволяет выполнять следующие инструкции, не дожидаясь результатов предыдущих, если там нет прямой зависимости. Как если вы, скажем, долго что-то считали в ymm1
, потом сохранили это в память, сделали xor xmm1, xmm1
и стали дальше считать уже на xmm1
— без vzeroupper
некоторые микроархитектуры будут предполагать наличие зависимости последующих считываний xmm1
от предыдущих записей в ymm1
, и не начнут их (замапив xmm1
в другой физический регистр и считая в нём), хотя вы xmm1
привели явно в конкретное состояние. Здесь скорость обнуления старшей половины ни при чём. Совсем. Вообще.
Ну или Вы занимаетесь только частью работ в реализации HFT, не понимая и не зная целого, что опять таки говорит совсем не в Вашу пользу.
Разделение труда — не слышали про такое?
Я в курсе, что с демагогом дискутировать смысла не имеет. Так что до тех пор, пока Вы не укажете, каким образом теория типов связана с пониманием работы компьютера, ответа от меня не увидите.
Учитывая, что я уже указал, почему требование ответа необходимости теории типов для понимания компьютера не имеет никакого смысла в данном разговоре (потому что изначально вы вообще не про понимание работы говорили, и потому что я как раз доказываю отсутствие этой необходимости для вашего исходного тезиса), отсутствие ответа будет означать ваш слив под весьма надуманным предлогом, не более.
И, кстати, заодно отсутствие указания метода расчёта паразитных ёмкостей в каком-нибудь современном интеловском проце с достаточной точностью для точной оценки задержек кешей, чтобы её потом не нужно было валидировать бенчмарками — это тоже слив.
Но это нестрашно, можете продолжать рассказывать всем про важность знания pn-переходов.
Может я и некропостер, но пояснение такое.
Когда синьор работает с технологией Х - ему оптимально понимать на 2 уровня абстракции "вглубь" что происходит (2 - эмпирически выведенная цифра).
Понимать более чем на 2 уровня абстракции нет надобности. Хотя если вам по-кайфу нагружать свой мозг именно этими знаниями - отлично.
Ок, спустимся ещё на уровень ниже: кто знает ответ на вопрос - а что такое электричество? Это я к тому, что уровень абстракции не может быть абсолютным.
Я выше указал на это. Не надо даже опускаться до уравнений Максвелла - Лоренца или Феймановских лекций по КЭД. Достаточно добавить кроме ключевого усилительный режим транзистора, чтобы объем информации из относительно незначительного превратился уже в такой полноценный курс ВУЗа, как знаменитая монография-учебник Хоровица и Хилла "Искусство схемотехники". Изучение этого труда дало мне очень многое, но уже не столько для программирования (в embeded пригодилось не раз), сколько для DIY проектов.
Так же я указал, что не могу утверждать необходимость описанных мной базовых знаний для программирования. Я лишь утверждаю, что эта база мне лично помогает до сих пор. Может это только у меня такой специфический склад ума, что я всегда копаю вглубь?
Мне кажется, что любая хорошая подготовка требует копнуть немного ниже, чем то, что приходится изучать. А вот дальше начинаются вариации: как глубоко копать - дело индивидуальное. Мне, к примеру, хватило представления о петле гисерезиса и машины Тьюрингка с теорией фон Неймана. Как, например, на нижнем урвне устроено деление, я так и не понял :-) Ну а Вам потребовалось понимание того, как работает транзистор и схемотехника.
Так я собственно говоря и оставил этот вопрос открытым: "Может всё же подобная база была бы полезна при обучении программированию?"
А не зная этой базы Вы и не можете судить о том, помогает она в программировании или нет. Вы можете лишь говорить о том, что насущной необходимости в ней не испытываете. А это всё же разные вещи.
Грубый пример. Испытывает ли шиномонтажник насущную необходимость в знании моментов затяжки колесных гаек в зависимости от вида диска, размера и шага резьбы? Нет. Ему на глаз даже удобней затягивать, чем динамометрическим ключом. Поможет ли это знание ему в работе? Да.
Может это только у меня такой специфический склад ума, что я всегда копаю вглубь?
Вглубь оснований математики вы же не докопали. Вы даже не докопали до разницы между «быть IT-профессионалом» и «глубоко понимать физические основы работы компьютера», поэтому можно переставать пытаться делать вид, что вокруг — зубрилы, а вы — зрящий в корень.
Ну Вы даже на одну публикацию здесь не накопали, так что цена Вашему мнению - нулевая )))
Мнения не зависят от количества публикаций.
Дальше что, попросите диплом о ВО?
Мнения - не зависят. Их цена - непосредственно зависит от вклада в Habr. А вклад тут можно внести только публикациями.
Цена мнений-то тоже не зависит (извиняюсь за слишком сжатую фразу в прошлом комментарии). Цена зависит только от того, насколько это мнение обосновано.
Вы сами рядом писали, что «тут не принято догматическое мышление», и при этом сейчас же демонстрируете ровно его, когда ценность мнения у вас связана с социальным авторитетом говорящего.
Более того, вместо попытки выяснить, в чём разногласия, и поступить с ними соответствующе (что делал я), например, попытавшись разъяснить, почему вы уравниваете глубокое знание устройства компьютера и статус IT-специалиста, вы выбрали стратегию «а у тебя на ноунейм-акке публикаций нет, азазаз)))». Почему? Потому, что вы на самом деле понимаете, что никаких рациональных аргументов у вас нет, а если таки признать, что вам по историческим причинам просто интересны определённые (и весьма узкие) глубокие части IT, то это не позволит вам больше говорить, что вы «всегда копаете вглубь» или что «все остальные зубрилы, ведь характеристики кэша Skylake-X спокойно выводятся из его схемы, зачем их запоминать или пользоваться справочником»
.
Почему? Потому что кое-кто удалил предыдущий, где статей было штук 25.
Это всё равно не влияет на вес моего мнения, кроме как в нулевом приближении (которое скучное, и не надо к нему апеллировать).
Они вообще сохранились?
Кое-какие (исходные английские версии) — в моём стандалоне. То, что не сохранилось, либо уже не актуально (ну толку-то брать производные на C++14 в 2025-м году), либо — не-хардовый буллшит.
Ну это было некоторое свинство, хочу отметить. Оно, конечно, обоснованное, но очень эгоистичное.
Кстати, если перейти к причинам удаления, насколько я их представляю.
Должен сказать, что я не чувствую, что до конца понимаю, где именно проходит разница в мировоззрениях между социалистами (я) и либертарианцами. И вообще не понимаю саму логику либертарианцев с их борьбой с регуляциями.
В рамках марксизма, который вроде бы не отрицается, государство США - выразитель воли правящего класса. Правящим классом являются крупнейшие корпорации и финансовые организации. Этот класс себе сделал бюрократический аппарат, который наделил определённой властью.
Бюрократический аппарат фигарит определённого свойства регуляции, которые есть результат договорённости правящего класса, чтобы не разнести доску. И в конечном итоге, то, что мы наблюдаем - это результат самоорганизации тех самых независимых акторов, которые всё укрупнялись и укрупнялись.
И регуляции, если они есть, то они нужны именно правящему классу. То есть, являются результатом договорённости достаточно крупных субъектов.
Кстати, если перейти к причинам удаления, насколько я их представляю.
WOK скандалы интриги расследования
За менее чем 24 часа я в двух разных тредах встретился с ответами мне от этак пяти разных людей, которые сводились к «сначала подмети у себя в подъезде, а потом критикуй правительство» и «если тебе не нравится правительство твоей текущей страны, чё ж ты не уедешь», и все из них были очень положительно поддержаны сообществом. Во втором случае один из высказывавших этот тезис людей в ответ на вопрос, что раз сообщество очень не любит этот аргумент в адрес default country, так почему же оно его одобряет сейчас и почему сам человек его считает нормальным аргументом, сказал по сути, что всё норм, он не видит проблем и параллелей.
И я вдруг подумал, что а зачем вообще я трачу свой labor day на то, чтобы доказывать что-то в рамках дискурса, где доказательство не котируется, а котируются эмоции и демонстрация принадлежности к группе, вместо того, чтобы писать код для себя или пойти погулять, в конце концов (гулябельная погода днём в Техасе бывает не так часто, увы, особенно в начале сентября). Ну и подумал, что другие методы едва ли сработают (потому что практика показывает, что я не могу просто пройти мимо политических дискуссий), написал админам «удалите аккаунт плз», и пошёл в парк погулял, а потом пописал немного кода. 10/10, не жалею, рекомендую, и единственная причина, почему я тут сейчас — было бы неплохо опубликовать одну статью для самого себя лично, из эгоистических соображений.
Лицемерие и неконсистентность — это одна из немногих вещей, которые я фундаментально не переношу, а тут вот и обычное лицемерие, и на метауровне.
Должен сказать, что я не чувствую, что до конца понимаю, где именно проходит разница в мировоззрениях между социалистами (я) и либертарианцами.
Вероятно, самая важная и хорошая нетехническая книга из всех, что я прочитал за 2024-й, если вообще не за последние лет десять — это на самом деле две книги: «A Conflict of Visions» и «The Vision of the Anointed» Соуэлла (в таком порядке).
Самое хорошее там в том, что там, в принципе, не описано ничего принципиально нового — я всё это знал и замечал и до чтения этих книг. Просто Соуэлл из этих наблюдений выводит очень простой и очень фундаментальный базис, по которому раскладываются позиции по всем «прикладным» вопросам, и который обладает неплохой предсказательной силой. Это как профункторы в теоркате: после того, как ты про них узнал, ты их везде видишь. Так и тут после того, как ты узнал про этот базис, ты его уши везде видишь, от новости о том, что байденовский назначенец-прогрессивист в минобороны хочет начать разоружение со своей страны («хаха, конечно, абсолютно логично, удивился бы, если бы было иначе, classic Sowellian unconstrained vision»), заканчивая статьёй здесь на хабре о научной фантастике, где человек с левыми воззрениями негативно отзывается о уоттсовской «Ложной слепоте», потому что Уоттс не верит в людей:
Товарищи гики! Доколе жанр, сказавший когда-то «Человек, ты бог», будет твердить упадническое «Человек, ты прах»? Чернухе в фантастике, цысиневщине и уоттсовщине бой! Палкой ее лупим, палкой!
(«хаха, конечно, абсолютно логично, удивился бы, если бы было иначе, classic Sowellian unconstrained vision»).
А контрпримеры к этому базису найти очень тяжело. Все случаи, что я встречал, объяснялись тем, что у человека вообще не было никакой позиции и мировоззрения, и он просто повторял те слова, которые слышал в наиболее важных для него частях его тусовки.
Либертарианцы у него там, кстати, несколько отдельно, и он считает их не входящими в описываемую им дихотомию, но я склонен считать анкап выкрученным на максимум, доведённым до логического конца constrained vision.
В общем, если есть десяток-другой часов на чтение написанной удивительно простым (для политической литературы) языком книги, то я настоятельно рекомендую прочитать хотя бы первую. Соуэлл объясняет эту разницу в мировоззрениях куда лучше, чем я когда-либо смогу.
В рамках марксизма, который вроде бы не отрицается
Кем не отрицается? Либертарианцами? Политическими экспертами?
Марксизм отрицается даже Поппером в его «open society and its enemies» (хотя я бы Поппера по ряду высказываний занёс бы в соуэлловского unconstrained vision'иста и вообще wishful thinking-этатиста, мне эта книга страсть как не понравилась).
И в конечном итоге, то, что мы наблюдаем - это результат самоорганизации тех самых независимых акторов, которые всё укрупнялись и укрупнялись.
А если вы биолог, то вы должны быть против поиска лекарств, потому что болезни — результат естественной биологической эволюции?
Либертарианство оставляет за агентами полное право выражать недовольство, указывать на неэффективность, и так далее, остальных агентов. Это как раз и есть одна из тех самых сдержек и противовесов.
Более того, либертарианец вполне может говорить, что институт репутации первичен, ибо не допускает укрупнения или поддержания жизни достаточно крупных агентов, чтобы они были net negative по влиянию.
Советуете почитать конкретно с точки зрения честности изложения? Мне сложновато читать английский Соуэла - поэтому спрашиваю.
===================================
Объяснение почему спрашиваю, возможно маловажное.
С одной стороны - очень крутой автор (почти как Фридман) в смысле объяснения сложных концепций простыми словами.
С другй - у Фридмана в 20 часах выступлений я вроде не нашёл обмана. У Соуэла в Basic Economics - просто постоянно biased примеры.
И в какой-то момент дошёл до почти подтасовок (ну условно сравнил мат-ожидание "парвильной страны" с медианой "неправильной страны")
Советуете почитать конкретно с точки зрения честности изложения?
Я не нашёл существенных изъянов и биасов, особенно в первой из книг. «The Vision», конечно, биаснута, потому что показывает ментальную акробатику соответствующих людей, но каких-то серьёзных косяков и там не заметил (хотя, опять же, не со всем согласен).
У Соуэла в Basic Economics - просто постоянно biased примеры.
Basic Economics у него я не читал, а, кстати, интересно!
(ну условно сравнил мат-ожидание "парвильной страны" с медианой "неправильной страны")
Для некоторых распределений это норм, кстати. И чем более равномерное распределение (если говорить о доходах, например, к этому вроде даже стремятся), тем ближе матожидание к медиане.
Точно математика, из курса прикладной теории цифровых автоматов помню что "бит" - это чисто математическая величина, логарифм по основанию 2 отношений вероятностей. Есть ещё "дит" - логарифм по основанию 10, и "нит" - логарифм натуральный.
Иногда думаю, что мне повезло, что я начинал со паскалей, бейсиков и си.
Базовое понимание как хранится число в компьютере, что такое ссылка и т д очень помогают.
Самое лучшее представление тут даёт python благодаря легаси. Ты описываешь метод как method(self, a, b, c), то есть явно показываешь, что self - это специальная переменная, хранящая ссылку на сам объект, на структуру его данных в памяти.
Мой момент осознания был, когда базовые навыки в схемотехнике и программировании сошлись в понимание, как я ошибался в детстве.
Я слышал "кристалл" процессора и искренне думал, что это специальный полированный камень, который вот как то так магически умеет, условно, перемножать напряжения чисел.
Ну не может же это быть просто большая схема с переключателями, она же будет ужасно сложной!
Да, это именно такая схема.
я начал с Кенгурёнка и Пылесосика :) А уже потом Паскаль
Что-то на богатом)
В детстве наверняка это бы дало какое то представление, но Я познакомился с ЯП только в колледже. Так что бэйсик в самый раз.
Я и сейчас считаю, что эти языки для обучения очень неплохи для начала, хоть и не очень практичны, в смысле того, сколько нужно учить для перехода на популярные языки с управлением памятью. С другой стороны условный питон прост, но оставляет тебя один на один с магией.
Я начинал с паскаля. А вот С++ начинал учить с MFC. Хотя и был уже знаком Delphi и было полно энтузиазма, все сложно было стартовать. Помню (хоть убей) не мог нормально понять что такое сериализация (это я так к примеру).
Да, желание по обучению программированию (особенно новичков, которые решили посмотреть что это такое) может здорово оттолкнуть. Достаточно даже относительно сложной литературы.
Встречались книги что с опытом в IT в 10+, просматриваешь и обалдеваешь от того что там написано и терминологии в частности.
Да, так то много было сложных тем.
Мы, к примеру, проходили assembler. И я сделал какую то программу с прыгающей точкой.
Но тогда мне так и не объяснили, что такое регистры на самом деле и почему структура такая странная.
Гораздо позже стало понятно, что это завязано на реальную архитектуру компьютеру.
У нас по assembler была еще та тетя. «живой процессор» Знала его круто и архитектуру тоже.
Но это все было на первых порах обучения. И вообще ничего не понятно. У нас один паренек (до сих пор помню): сидит раскручивает стул, я: что ты делаешь? Да, что она как с психушки несет.
Потом купил себе книгу (из топовых) по assembler. Но так руки не дотянулись.
Компьютер - это камень, работающий на магическом дыме. Если компьютер использовать неправильно, то магический дым выходит и компьютер перестает работать!
Непонятки с программированием фигня по сравнению с развертыванием проектов, вроде в теории все понятно как, но на практике ничего не работает и непонятно почему, а современный программист "должен уметь все".
Забудьте всё, что учили в университете (C)(TM)(R)
Ага, а самоё весёлое, когда на твоём стенде всё работает, а у заказчика ничего не работает. Конфиги вроде одинаковые, всё вроде одинаково, но не работает. И вот сидишь часами в созвоне с заказчиком и просишь их дёргать разные штуки чтобы понять что именно не работает и почему. Спустя пару дней разница в конфигах находится и разница в инфраструктуре тоже.
Для этого и начинают с базовых вещей, а не с высших концепций. Линейный код, ветвления, циклы, простые типы, не сразу классы с их конструкторами. На следующий уровень надо переходить, когда становится тесно на текущем.
Вообще считаю что сразу переходить к ООП - вредно. Я из-за подобного подхода долго не понимал, что бывает вообще как-то по другому. Данные - это просто данные, нет никаких классов, методов, наследования и так далее.
Это вот прям база. Я не сразу до этого дошел. Привык учиться "сходу". Так нельзя в программировании. Надо хорошенько провариться на своем уровне. Как ты сказал, чтобы "тесно" стало.
Было непонятно, какой физический смысл в классах.
Не, примеры «класс «машина» с атрибутами «бак» и «колеса» и методом «ехать», наследование от этого «грузовик» и «легковушка» и всё вот это» - понятно и ребенку. Или там класс «Users» и всё вот это.
Но совершенно непонятно, зачем этот странный танец, и главное: когда мне надо написать программу, то с какой стороны подходить, чтобы эти самые классы спроектировать? Вот у меня есть бизнес-задача, в ней надо вычленить что-то, что в дальнейшем описать как класс. Как это углядеть? Как «расчленить» реальность, чтобы я увидел: да! Вот он, будущий класс, и вот зачем он мне, и вот так он будет устроен. Все гуру твердят - анализируйте задачу, вычленяйте классы… Как анализировать? С какой стороны надо взглянуть на задачу, под каким углом ее рассечь, чтобы я увидел необходимость описывать что-то в ней как класс?
Долго не включалось понимание. Помог мой старый учитель, сказав «Заголовок таблицы - это атрибуты, а названия колонок - имена атрибутов. Строки таблицы - экземпляры класса. Дальше сам».
И как пелена спала с глаз.
Хм, отличное объяснение, но только для тех, кто уже знаком с реляционным БД.
Я несомненно был знаком. Мой преподаватель до этого мне преподавал как раз это самое на примере Access и иже с ним. Но в принципе достаточно знакомства с табличными процессорами.
Кстати, я впервые увидел табличный процессор на “Поиске” в 1993 году - это был SuperCalc. И сейчас я очень жалею, что тогда не осознал всю его мощь.
Или с таблицами Excel
Да просто если хотя бы раз в жизни видел эксел
Всё что более одного и не умещается в формат встроенной переменной - класс, т.е. приходится расширять язык по типам
«Заголовок таблицы - это атрибуты, а названия колонок - имена атрибутов. Строки таблицы - экземпляры класса. Дальше сам».
И как пелена спала с глаз.
Риали? Я я с 30+ годами в программировании вообще ничего в этом не понял. Особенно поразило это - Заголовок таблицы (единственное число) - это атрибуты (множественное число). Пол-дня размышляю. Я так понял вы про таблицы в реляционной бд? Но почему атрибуты - это заголовок?
названия колонок - имена атрибутов - атрибуты это заголовок, а их имена - названия колонок? Что бы это могло вообще значить?
С какой стороны надо взглянуть на задачу, под каким углом ее рассечь, чтобы я увидел необходимость описывать что-то в ней как класс?
Я догадываюсь, что вы таким странным образом пытались описать ORM, но ведь маппинг данных на объекты - это не только не исчерпывающее объяснение, но, вероятно, едва не самый незначительный способ использования объектно-ориентированного проектирования.
Впрочем, это не так уж важно, если в вашем случае это помогло, главное - результат. Просто фраза "заголовок - это атрибуты" сильно поразила :)
Мне помогло многократное чтение книги Гради Буча (не самое понятное изложение, но подсказка в какую сторону думать) и, потом банды четырёх (это уже во многом закрепление вида - ах, вот как это называется!).
Все гуру твердят - анализируйте задачу, вычленяйте классы… Как анализировать?
У вас получается data driven подход к анализу. Мне кажется, более полезен, не знаю как назвать, - behavior driven анализ, может быть?. Ответ на вопрос - что нужно делать? А "над чем это что-то делать" - сложится само :)
«А че ты такой серьезный?» (с)
Я где-то утверждал, что это - истина в последней инстанции? Я всего лишь показал, как одна фраза помогла сдвинуть моё тупое непонимание с мертвой точки.
Конечно же, всё гораздо, гораздо сложнее. И классы бывают очень разными, и сам я такие загогулины сочинял, что уж точно их не опишешь как таблицу. И фраза, кстати, звучала не точно так, это я так ее примерно воспроизвел, как оно мне понялось и вспомнилось через десяток лет. Дружище, еще бы дипломную работу написал в опровержение…
«…че ты такой серьезный?»
Вот у меня есть бизнес-задача, в ней надо вычленить что-то, что в дальнейшем описать как класс. Как это углядеть?
Вообще-то, вопросы проектирования задачи не являются вопросами программирования. Это разные этапы решения задачи в целом. Начальный этап поиска решения включает в себя такую вещь, как анализ исходного материала. Сам процесс познания чего-либо предполагает разбиение чего-то целого на функционально связанные, но обладающие собственными (имманентными) свойствами части - это, по простому, и есть анализ. Затем происходит абстрагирование этих частей, то есть, поиск сути (сущности) для каждой из таких частей путем отбрасывания неважных, в рассматриваемом контексте, свойств или особенностей. Выделяемые при этом сущности описываются с помощью формального языка в виде некоторых структур, называемых классами. А итоговое решение задачи представляет собой набор таких описаний и построение на основе этих описаний так называемых экземпляров классов - программных объектов, взаимодействующих друг с другом путем посылки сообщений (это так определяется, скажем, обращение к методу объекта). Собственно, объектно-ориентированный подход - это всего лишь способ, позволяющий справиться со сложностью поставленных задач, не более того.
Если программист не видит необходимости в использовании классов и ООП, то это означает, что поставленная перед ним задача либо слишком проста, либо он до конца не осознаёт её сложности.
Я когда первый раз взял в руки Python, ну вот вообще первый раз… естественно, не читая никакой документации. Ну просто решил, что это такой Бейсик с упрощенным синтаксисом. Ну и, поскольку я был тот еще прогромист, решил использовать так любимые новичками нумерованные переменные (о списках не имел понятия). И не приходя в сознание накарябал на этом питонобейсике инструменты себе для создания, перебора и удаления нумерованных переменных в глобальной области видимости. А вы говорите - классы…
Если программист не видит необходимости в использовании классов и ООП, то это означает, что поставленная перед ним задача либо слишком проста, либо он до конца не осознаёт её сложности.
Периодически пишу компиляторы (в основном те части, что отвечают за тайпчекинг), не вижу смысла в использовании классов и ООП. Это слишком простая задача или я не осознаю её сложности (и как в таком случае ООП может помочь по сравнению с обычным ФП и беготнёй по деревьям, как это делается в ML-языках)?
Но это так, лирика. Просто если подходить к проектированию с точки зрения domain-driven design, то и разбиение предметной области будет достаточно естественным, и окажется, что ООП не очень-то и нужно (и книга domain modeling made functional тут топ).
Либо ООП не подходит конкретно к этой задаче.
Вот скажем в бэкэнде оптимизирующих компиляторов использование классов идёт поперёк всей логики.
Я рискну расширить "бэкэнд оптимизирующего компилятора" до "сильно алгоритмических задач" вообще. В них очень часто довольно сильное взаимо-проникновение структур данных друг-в-друга (high cohesion).
В итоге в ООП вызовов-обёрток больше, чем содержательного кода.
Взялся недавно "научить программировать игры" 15-летнего племянника, совершенно нулёвого в ИТ, хотя очень интересующегося. Опустим подробности того, как нелегко в принципе чему-то научить чела из поколения альфа...
Сам я довольно давно закончил ВУЗ по специальности "микроэлектроника" (если кратко), начинал программить с машкодов/ассемблера/си/и т.п. по восходящей. Своего опыта обучения других, а тем более детей, в своей области практически не было.
Прочёл пункты "непоняток" в статье. Всё так - это действительно ни фига не понятно, и довольно трудно объяснить человеку, не прошедшему такую же "школу", как ты сам.
Для меня было шоком, насколько сложно объяснить самые простые понятия в программировании (язык тут не важен). Копал вглубь и в ширь, на палочках/яблоках/коробочках/полочках объяснял самые элементарные вещи про хранение данных, архитектуру условного процессора, взаимодействия с ОЗУ, шинами и устройствами. Пока он всё это не понял (как мне показалось), даже не двигался в сторону алгоритмов вообще и синтаксиса конкретного ЯП, в частности.
Я бы не хотел такого преподавателя.
Игры хочется программировать, а мне зачем-то компьютер саенс объяснют, без яп. Оно когда нужно будет человеку, тогда и изучится.
мой малой в 10 лет без всего этого научился в скретче и циклам и переменным и игры уже делает.
Смотря какие игры и как программировать.
На юнити или скретче можно "программировать" игры с помощью чат-гпт, и весь процесс будет казаться магией (в которой не особо хочется разбираться, так как она отдана на аутсорс нейросетке). Польза от такого программирования сомнительная, хотя простая игра может получиться, замотивировав идти дальше.
Скилл программирования при подходе "напиши задачу или скопируй ошибку нейросетке" не растёт, и в результате получится очередной гпт-программист, не способный перевернуть строку.
Второй способ - начинать с CS, с машинного уровня. В геймдеве с этим скорее всего придётся столкнуться, когда речь зайдёт об оптимизации или минимальной защите игры от взлома. Но такой подход долгий и за 2-3 года может пропасть желание "изучать IT, чтобы делать игры", а игры не будет. Зато может появиться стремление к чему-то другому: бэк, фронт, мобайл, дизайн, десктоп, тестирование, аналитика и так далее.
Вопрос поиска баланса при запросе "хочу научиться делать игры" для меня остаётся открытым, уж слишком много надо для этого изучить, чтобы сделать что-то сложнее (а в большинстве случаев это именно так) гиперказуалок.
Мой список того, что нужно изучить, чтобы начать геймдевить на c++ / java / js:
0. Структурное программирование, операторы, типы данных.
Многофайловая структура программы
Main loop
Загрузка/выгрузка ресурсов (текстуры, звуки, модели, анимации)
Пайплайн рендера, opengl или vulkan
Шейдеры
Матрицы, кватернионы, линейная алгебра
Текстуры, форматы текстур
Форматы данных вершин, нормали, тангенты, кости, веса костей
Multi render target, framebuffer, отложенный рендер
Анимации (кости, кватернионы, матрицы, интерполяции)
Сеть - сокеты / http / websocket
Бэк, если есть сеть. Стек не важен, главное не пхп.
Многопоточность, синхронизация
Физика - какой-либо движок, aimo.js, bullet
Аудио
GUI, рендер элементов управления, рендер текста, статические и динамические шрифты
3д моделирование, текстурирование, риггинг, анимации
Список можно продолжать.
Возможно ли это уместить в 2 года обучения? - скорее нет, может ли это отбить желание делать игры? - скорее да. Зато, если пройти весь путь, то "хочу делать игры" будет осмысленным решением и скорее всего всё получится, так как не будет нпоняток и магии.
Давайте начнём с того что определим что вы понимаете под "скилл программирования".
Ну то есть это для вас именно "набор кода в виде текста в редакторе" или, если уйти в другую крайность, наоборот "процесс создания программ"?
Инди сапописцы не релизают игры, а бесконечно переписывают майнкрафт. В реальности движки популярнее кастома. Есть четверка - Unity, Godot, Unreal, XNA.
А знание vulkan не помогают делать "что-то сложнее гиперказуалок". Можно посмотреть реддиты движков, там есть посты саморекламы и порадоваться за людей использующих подходящие инструменты для задач.
Такую магию можно раскрывать вплоть до кварков, но это ни к чему не приводит. Мы математику изучаем не с Функционального анализа. Мы должны что-то принимать на веру, пока не разберемся в простых вещах. Ни юнити, ни чпт не помешает учиться, все-равно нужно узнать/увидеть синтаксис и к чему обращаться, а материалов сейчас очень много. Ну а как правильно обращаться придет только с опытом.
Комментарий к которому я отвечал, не преподавал никакого ЯП ученику, а исключительно теорию про железо. В чем смысл чистой теории оторванной от практики? Лабы/Проекты самое важное, а игры офигенный способ - мгновенный результат.
Программисты, страшно далеки они от народа.
Пайплайн рендера, opengl или vulkan
Мнэээ... вы никогда не видели Tetris, Pacman, Mario, Undertale, 100500 прочих, где это не нужно? И не видели готовых движков, которые берут на себя всё, им только дай описание типа "вот объект такой-то формы" и они дальше сами создают все пайплайны и зовут как надо всяких vulkan?
Начинать действительно нужно с самого простого. Если кто-то хочет в игры, то уже создание условного Pacman даст ему понимание про то, как реагировать на действия пользователя. Добавить спрайтов на неподвижном (или скроллимом) изображении и вот вам уже уровень Mario, Undertale, которые выстрелили как блокбастеры и шедевры даже при такой простой анимации. А дальше можно уже и про шейдеры рассказывать (и то, сейчас мало кто свои движки пишет).
На весь геймдев людей, которым действительно важно, как настроить те же шейдеры, ну пара десятков тысяч, может - и то потому, что на андроиде тебя кидают голой грудью на то, что надо их писать без промежуточных слоёв. Без этого было бы человек 500 на всю планету. А остальные занимаются другими задачами. Кто-то NPC пишет на языке уровня Lua, кто-то серверную логику, например, на Go, есть ещё множество вариантов, по знакомым сужу...
Мой список того, что нужно изучить, чтобы начать геймдевить на c++ / java / js:
"Начать"? Да после этого - если с реальным опытом - получится full-stack многостаночник, которых не бывает. Вы своим списком как раз дали классический пример - как и куда не надо идти для обучения программированию...
(Я не говорю, что про это не надо читать или вообще знать. Надо. Надо прочитать книжку или хотя бы туториал по каждому из, чтобы понять задачи и проблемы смежников. Но не "изучить".)
Мде. А потом у людей возникает вопрос "что такое переменная и зачем оно надо".
И тупняк на собеседовании в качестве ответа на вопрос с переполнением типа
Мда и причем тут собеседование и переменные? Ребенка, зачем регистрам и шинам учить?
Это знание про переполнение ничем не примечательное. Просто факт который узнаешь за 5 секунд и запоминаешь.
Common sense нужно подучить
Это знание про переполнение ничем не примечательное. Просто факт который узнаешь за 5 секунд и запоминаешь.
100% примечательное. Надо понимать и всегда чувствовать, что у переменной есть тип. (Если типизация динамическая - то у значения есть тип.) У типа есть свойства и ограничения. Нельзя в число впихивать строку, и наоборот (ну да, можно, если вы согласны, что через NaN минут к вам приедет [object Object], но обычному заказчику такое не понравится). Нельзя пихать float значение в integer переменную, не получив гарантию, что вас устраивает усечение или там точно целое. Переполнение - один из индикаторов несоответствия типа или проблемы с операцией над типами. Дальше чисто дидактический вопрос - типизацию и последствия её нарушения на чём показывать? Возможно, переполнение тут не лучшее для первого показа, но что оно "примечательное" - в смысле, что надо знать про него - это "к гадалке не ходи".
Копал вглубь и в ширь, на палочках/яблоках/коробочках/полочках объяснял самые элементарные вещи про хранение данных, архитектуру условного процессора, взаимодействия с ОЗУ, шинами и устройствами. Пока он всё это не понял (как мне показалось), даже не двигался в сторону алгоритмов вообще и синтаксиса конкретного ЯП, в частности
Неудивительно, что с таким подходом ученик долго не въезжает в программирование и тупит на, казалось бы, очевидных вещах. Ведь ему объяснили всё, кроме нужного!
Гораздо проще и понятнее объяснять, начиная с понятия алгоритма и рисования алгоритмов на бумажке. А затем сказать: компьютер - это исполнитель алгоритмов. Чтобы он что-то сделал, его нужно попросить об этом на понятном ему языке (т.е. ЯП), описать алгоритм. Этого достаточно, не вдаваясь в технические подробности его работы. Их (особенности архитектуры процессора, многопоточность, шины памяти и т.д.) поначалу либо вообще не стоит упоминать, либо дать в формате интересных фактов для любознательного читателя (не понял - не страшно), а если очень надо объяснить какую-то особенность работы программы или компилятора - использовать формулировку "по техническим причинам".
Гораздо проще и понятнее объяснять, начиная с понятия алгоритма и рисования алгоритмов на бумажке.
Что сразу отвратит примерно половину нынешних учеников.
А затем сказать: компьютер - это исполнитель алгоритмов. Чтобы он что-то сделал, его нужно попросить об этом на понятном ему языке (т.е. ЯП), описать алгоритм. Этого достаточно, не вдаваясь в технические подробности его работы.
Недостаточно, потому что большинство не понимают, пока их не ткнут носом в, основной проблемы: компьютер ничего не может додумать, он предельно механически делает то, что видит. И это недопонимание лечится только набиванием шишек "как он может этого не понимать, я же понимаю? oh wait..."
Я читал, что какой-то опытный учитель преодолевал это так: давал ученикам задачу командовать точную последовательность действий просто чтобы дойти от кафедры до двери класса, и повторял 1:1 что они говорят. Раза с десятого они начинали понимать проблему и задавать с точностью до "продвинуть левую ногу вперёд в полусогнутом состоянии".
а если очень надо объяснить какую-то особенность работы программы или компилятора - использовать формулировку "по техническим причинам".
Да, для начала надо именно так. Потом начинать уточнять эти причины, где нужно.
Я помню, что мне отец (инженер-микроэлектронщик) принёс ZX-Spectrum и стал что-то объяснять. Я ВООБЩЕ НИФИГА НЕ ПОНЯЛ.
Через год или два - поступил в компьютерный класс. Там ВООБЩЕ ВСЁ ПОНЯЛ. Причём программирование меня вставило вот уже на 26 лет с тех пор.
По прошествии лет - списываю это на то, что микроэлектронщики очень плохо умеют объяснять высокоуровневое программирование (структурное программирование и выше - высокоуровневое).
А зачем вообще объяснять, что такое int8/16/32/64? На раннем этапе достаточно объяснить, что uint8 - это "от 0 до 255", а int8 - "от -128 до 127". Просто запомнить как аксиому. И вообще использовать просто int.
А уже потом, когда объяснили, как работает процессор и память, что такое бит и байт, можно объяснить, что int делится ещё и на все эти 8/16/32/64/128. Плюс есть unsigned (uint), long/ulong и прочие типы.
Это на самом деле важно, потому что компилятор не всегда достаточно умный, и, если не знать представление отрицательных чисел, то можно надолго застрять со странными результатами деления беззнакового на знаковое и подобным.
Это всё становится важно, когда уже знаешь азы языка и начинаешь углубляться в оптимизацию и отладку.
А в начале достаточно объяснить, что "int" - это для целых чисел, а "float" (double) - для дробных. Ну и упомянуть о ограничениях мин/макс значения.
Для написания простых приложений и понимания языка в целом - этого достаточно.
А всё остальное изучается после, как дополнение под названием "оптимизация работы программы". (скорости выполнения и стабильности)
Кажется, что вы нагоняете мути на пустом месте.
При всей сложности подкапотной машинерии на практике the thumb rule крайне простое:
или v1 : используйте или только знаковые или только беззнаковые.
или v2 : используйте числа одинаковой длины.
(разумеется мы помним, про переполнение UB-переполнение знаковых, которое кажется вскоре пофиксят).
Если приведёте контрпример к написанному выше - буду благодарен.
Согласен на 100%.
На базовом этапе с лихвой достаточно знать, что сеть int, string и boolean.
В свое время не разу не видел в книгах чтобы сразу в такие подробности вдавались.
И еще, после трех пройденных курсов по Python - если всё делать по рецептам из курсов, всё работает. По аналогии - тоже работает. Но почему в одном случае они ставят квадратные скобки, а в другом - фигурные? Не, про список понятно, словарь - понятно, это типы данных. Кортеж понятно. Но почему я не могу просто что-то взять в скобочки для удобства без последствий? Причем в скобочки удобного мне вида?
Поиск в Гугле по этой теме тоже мало что дал. Пока мне не порекомендовали Лутца. Вот после его книги всё стало ясно.
Про переменные я еще лет семь назад рассказывал на одном из Moscow Python Meetup. Концепция нифига не простая 😳 https://youtu.be/js7aP3A_4Ts
Одна была у меня непонятка, но фундаментальная, из-за которой я и не стал программистом - это "объектно-ориентированность". Так я и не научился мыслить классами, не смог понять зачем все эти наследования, полиморфизмы, интерфейсы...
люди любят всё усложнять )
Берется концепция класса как таковая - например та же "мебель": у нее есть ножки, N штук, и ее можно поставить на пол.
Делается класс "табуретка" с 3 ножками, класс "стул" с 4, класс "стол" тоже с четырьмя другой высоты - вот это наследование. Пока всё просто и логично, у всех общий метод "поставить".
А потом программиста переклинивает, и он начинает создавать класс "велосипед" с 2 ножками колесовидной формы, с функцией вращения, класс "квадрокоптер" с 4 ножками с функцией пропеллера, а так как поведение ножки стула и пропеллера отличается - начинается полиморфизм...
Всё хорошо в меру, и обьектно-ориентированность тоже.
Люди любят всё усложнять - пока вам ВОТПРЯМЗДЕСЬИСЕЙЧАС не нужны классы - вам не нужны классы. Пользуйтесь переменными. Хоть для мебели хоть для геометрической фигуры.
Через пару месяцев сами такую "мебель" захотите вернуть из функции - оп у вас структуры.
Ещё через пару месяцев сами захотите к этой мебели приделать "действия" - оп у вас классы.
Ещё через пару месяцев запутались как эти классы наследовать - и только теперь вам нужна книжка по ООП.
Просто не забивайте себе голову всеми этими умными словами и используйте классы как некую разновидность struct (структуры данных) с возможностью встраивать функции. Ну или как "контейнер" внутри которого можно спрятать переменные и функции... Собственно, для этого их и придумали - изоляция переменных и кода внутри классов.
Кстати, пониманию ООП сильно способствуют изначально ООП-ориентированные языки, вроде C#, где даже базовые типы (int/str) являются объектами (классами).
Во! Фраза "используйте классы как некую разновидность struct" - это как раз тот случай, когда для говорящего есть нечто само собой разумеющееся. Я начинал с Delphi (или Object Pascal, не знаю как он сейчас зовется), потом перешел на C# и даже сделал на нем пару проектов. Просто я изначально не вкурил тему ООП и делал все неправильно, а потом переучиться уже не смог. Проще учиться с нуля, чем с минус 100500 :-))))
Хмм... Окей:
"Классы" из ООП - это отдельные файлы, в которых могут быть свои переменные и функции. Все эти переменные и функции существуют внутри этого "файла", но к ним можно обращаться из другого файла. Так будет проще?
C#, где даже базовые типы (int/str) являются объектами (классами).
Классом является только строка. Возможно, все же стоит забивать голову.
https://github.com/dotnet/runtime/blob/main/src/libraries/System.Private.CoreLib/src/System/Int32.cs
Ну ок, не класс, а структура, что, впрочем, почти тоже самое в случае с C#.
В любом случае - "всё есть объект". Это основная парадигма (девиз?) языка, если мне память не изменяет.
** Речь про .net C#... Может я что-то пропустил и появились другие варианты "си-шарпа"?
Ну ок, не класс, а структура, что, впрочем, почти тоже самое в случае с C#.
Теперь дело за малым, осталось объяснить что такое "структура" .
В любом случае - "всё есть объект".
И что конкретно вы понимаете под словом "объект"? :)
Это основная парадигма (девиз?) языка, если мне память не изменяет.** Речь про .net C#... Может я что-то пропустил и появились другие варианты "си-шарпа"?
Вот именно в C# "int" относится к примитивным типам данных и не является объектом.
** и конкретно в C# не стоит путать int и Integer :)
Вот именно в C# "int" относится к примитивным типам данных и не является объектом.
Неправда ваша. Тип int (для .NET Framework или Core - это сокращение для Int32) наследуется от типа ValueType, а тот в свою очередь - от типа Object, базового для всех типов. Правда, компилятор реализует его в коде как примитивный (или значимый, короче - не ссылочый) тип - переменная этого типа содержит само значение, а не ссылку на значение где-то в куче (но есть нюанс - упаковка). Но это уже не сам язык, а его реализация.
Мне интересно что вы понимаете под "не сам язык, а его реализация".
Особенно когда у нас "Речь про .net C#".
"Речь про .net C#".
Это другое , понимать надо. Фраза была про соответствие типа int языка и типа, используемого конкретной реализацией) . Для двух перечисленных исполняющих систем (да, их я перечислил две, а вы поторопились оборвать фразу) соответствие именно такое, а что там с другими (Mono, например) - выяснять мне откровенно лень.
Что касается object и того же int, то int можно свободно использовать там, где ожидается object: преобразование производится автоматически, как и положено для производного и базового типов. Именно так и следает понимать, что int является объектом. А то, что это преобразование нетривиально - требуется "упаковка"(boxing) значения int, т.е. размещение этого значения в куче - это уже деталь реализации.
Это другое , понимать надо.
Ок. Давайте я сразу уточню что память меня слегка подвела и я действительно ошибся. "Integer" он у нас в Java, а в C# действительно Int32.
При этом насколько я вижу, этот самый Int32, который наследует от ValueType и Object, это именно что "сущность" из конкретной реализации. То есть например из .Net.
Что касается object и того же int, то int можно свободно использовать там, где ожидается object: преобразование производится автоматически
И опять же вопрос что вы конкретно понимаете под "преобразование". Разве там не создание wrapper'а в вокруг примитива в int в виде того самого объекта класса Int32?
Разве там не создание wrapper'а в вокруг примитива в int в виде того самого объекта класса Int32?
Дык, на уровне абстракций самого языка C# это преобразование (boxing) не видно, и все на этом уровне выглядит так, будто его нет и не было. Пока сборка мусора не начнется ;-) - но это уже детали реализации.
Но эта абстракция - очень тонкий слой, через дыры которого явственно проглядывает реализация. И это не только внезапные перерывы на сборку мусора, но ещё и ограничения самого языка: например, наследовать от значимого типа запрещено. Ну, а дальнейшие рассуждения об абстракциях стоит вести IMHO только уже для конкретных применений.
Но в немалом числе применений абстракция "int - это наследник object" работает: int (и любой ValueType) можно присвоить переменной типа object без явного преобразования, для него можно вызывать методы object (к примеру, GetType(), чтобы узнать точный его тип, и т.д. Так что ваше утверждение "в C# int ... не является объектом" в общем случае неверно. Именно об этом я и написал сразу. А хранится в памяти он обычно по-другому, да, и это настолько существенно для практики, что об этом пишется даже в учебниках.
теперь осталось объяснить что такое структура
Не надо ничего объяснять. Пусть программирует (детские программки в песочницы).
Через пару месяцев захочет вернуть две переменных х и y - сам допетрит до структур.
Через пару месяцев поймёт, что с TPoint (надеюсь в C# codestyle такой) удобно что-то делать "изнутри" - сам поймёт что такое класс.
Через пару месяцев неправильно спроектирует иерархию "геометрических фигур"
И вот только когда человек способен сам сформулировать вопрос - ему пора давать книжку по ООП.
Ну ок, не класс, а структура, что, впрочем, почти тоже самое в случае с C#.
Это не почти тоже самое, это диаметрально противоположные вещи.
Классы - тип ссылочный, структуры - значимый. Разница фундаментальна в контексте шарпа и принципиальна при написании кода. Вы точно программист?
Вазовые типы кроме строки являются структурами.
и используйте классы как некую разновидность struct (структуры данных) с возможностью встраивать функции.
И тут же окажется, что это определение не соответствует ни ядерному интерфейсу файлов, ни какому-нибудь RPC с объектами, а тем более тем средам, где штатно объекты - это то, что обменивается сообщениями и имеет собственный источник жизни, не опираясь на потоки управления вызывающего (а к такому относится минимум Erlang-мир, а есть ещё Smalltalk и много чего).
у меня ситуация наоборот - я отлично понял всё это, полюбил и использую, а вот собственно с программированием как решением алгоритмической задачи - огромные проблемы, могу решить только самые примитивные случаи и задачи. Более того, я когда впервые понял ООП и научился писать через классы - я всё что угодно пытался тащить в те классы, надо и не надо))
Объект - это абстрактный предмет или явление, абстракция. Мы представляем что-то, что может что-то делать и имеет какие-то базовые свойства. Например, кубик (условно - игральный). Кубик можно кидать, из кубика можно строить башенку, кубик можно покрасить в какой-то цвет. Или перекрасить.
Интерфейс, соответственно - как описание кубика. Грубо говоря "нам пригодится что угодно - абы его можно было кидать, абы из него можно было строить, абы его можно было покрасить, если объект выполнит эти условия - мы готовы признать его КУБИКОПОДОБНЫМ и использовать в нашем коде" или даже "делайте что хотите - но абы из него можно было строить, бросать и красить"
И вот на основе объекта мы можем создать "экземпляр" (один инстанс) - как будто у нас был чертёж кубика и мы сделали по этому чертежу 1 кубик. И он прям кубик как кубик - соответствует интерфейсу, его можно бросать и из него можно строить пирамидку, это - его базовые свойства. И как у программной сущности каждый экземпляр имеет какую-то свою привязку-идентификатор, для которой мы в памяти записываем свойства только этого кубика - так мы их будем различать и сохранять индивидуально заданные свойства.
Ещё при создании экземпляра у нас используется метод "конструктор", в котором можно задать, чтобы, например, кубик сразу покрасили в красный цвет - тогда свойство экземпляра сразу после создания получит аттрибут - "красный": $this color = 'red'; и теперь в память для экземпляра именно этого кубика ($this) будет записано "красный". Ну а если этот метод оставить пустым - кубик создатся как есть и цвет можно будет задать/перезадать потом.
А потом приходит менеджмент и говорит: "да, классные кубики, но они из глины всегда делались, со временем грани оббиваются, мы вот тут думаем это исправить и заодно расширять ассортимент и будем делать кубики из дерева и из металла". То есть, для кубиков нужно прям новое свойство - материал, мы теперь его точно хотим знать и быть уверены в нашей продукции. Описание кубика останется таким же - "чтобы из него строилось, кидалось и цвета разные" - это значит, что интерфейс кубика менять не нужно, а нужно добавить новый атрибут для объекта "кубик" - для нашего "чертежа", на основе которого мы создаём экземпляры кубиков.
И мы возвращаемся на уровень выше - от экземпляра к объекту, которому даём новое свойство - material. Волшебным образом теперь все новые экземпляры кубиков будут иметь это свойство. Можно доделать метод "конструктор" так, чтобы он каждый раз спрашивал - из чего будет кубик. Ну нам не тяжело, будем указывать - дерево или металл.
Это - довольно важный момент в жизни любого объекта или библиотеки - когда мы что-то такое добавили, чего раньше прям не было. Все новые кубики будут деревянные или металлические, а если взять старый кубик - он будет "никакой" в плане материала. Это как раз тот момент в разработке программного обеспечения, когда заводят волынку про "обратная совместимость нарушена" и вот такие обновления обычно называют "мажорное" - update 2.0.1. 1 в данном случае означает версию какого-то мелкого дополнения, исправление ошибок, то есть - 1 раз что-то было мелкое сделано, 0 обозначает "минорные" обновления, когда мы добавили что-то новое, но оно не помешает использовананию старых объектов. А вот цифра 2 - это как раз "мажорное" изменения, то есть, нам уже не удастся использовать "старые" кубики, ведь у них не будет "материала" - а мы уже настроились поджигать кубики или магнитить (что менеджмент попросит), поэтому старые кубики прям совсем не подойдут.
----
Ну и "полирнём" "тремя китами" ООП: наследование, инкапсуляция, полиморфизм.
Инкапсуляция - это та невидимая работа, которая переводит наше взаимодействие с кубиком в физические изменения кода кубика, хранящегося в оперативной памяти и имеющего идентификатор. Грубо говоря, мы просто говорим, что этот кубик - красный - и он станет красным. Нам никто не вынесет конторскую книгу, мы не будем её всю читать и искать идентификатор именно этого кубика, разбираться - как он там в памяти хранится, он записан двоичным кодом или может, текстом или ещё как-то. И нам не нужно задумываться - а кто или что там объясняет, что из этого кубика можно строить что-то - "оно как-то само, где-то там, унутри".
А если бы наш "кубик" не был инкапсулирован (то есть не был классом) - нам бы приходилось вручную запрашивать идентификатор в памяти компьютера, выбирать из него объект, смотреть и проверять - а что мы там получили, где оно и что оно может или нет.
Соответственно, есть языки программирования, которые поддерживают инкапсуляцию, есть такие, которые не поддерживают - их называют "низкого" уровня, а первые, соответственно, "высокого". Отличие приблизительно как общение с очень опытным работником, который знает, где что лежит как работать - и как с совсем зелёным новичком, который прям не знает ничего нигде: с новичком нужно возиться и прям подробнейше ему всё разъяснять, где и что лежит и как делается, зато все те инструкции он будет выполнять чётко так, как вы ему сказали. А опытный работник будет всё делать с полуслова, но у вас уже не будет всего понимания - а где он взял этот гаечный ключ, который принёс - взял на складе, нашёл, украл, сделал сам.
Здесь к слову можно ещё добавить про "императивные" языки и "декларативные", там сходная ситуация: первые - это прям надо дотошные инструкции писать: "пойди вот туда, сделай 43 шага, найди шкаф, найди третью ячейку, найди там ключи, возьми самый большой, принеси сюда" - а вторый (например, код SQL или код HTML) - "иди принеси чем там гайки крутить". Оба вида нужны, да оба на своих уровнях, так и сосуществуют). Как правило, про декларативные языки говорят, что это не языки программирования - хотя проектировать (писать сценарии) на них тоже нужно)
Вернёмся к кубикам и посмотрим - что там с полиморфизмом. А ничего, это просто возможность делать экземпляры кубиков разными способами. Если кубик из дерева - ну хочешь - топором теши, или на деревопильном станке выпиливай или из бревна долотом выдолби - "мы доверяем вашему профессионализму")) А если кубик из металла - ну хотите - целиком отливайте, или на токарном станке выточить попробуйте, или там на лазерном ЧПУ-станке вырежьте - на не принципиально, пока его можно кидать, из него можно строить, его можно красить. В итоге мы будем иметь кучу полиморфных кубиков - будут сделаты по разному, а свойства будуть иметь нужные. Значит - их можно будет продать и менеджмент будет доволен: "какие молодцы наши разработчики - умеют по-всякому")))
Ну и осталось наследование. Пришёл менеджмент и говорит, мол, пользователи жалуются - если строить башню из кубиков - получается столб, некрасиво, вы там добавьте новый кубик - который крыша. Получается, теперь нужно 2 объекта: кирпичик (кубоид, 6 граней) и крыша (пирамида, 5 граней). Вроде бы интерфейсно всё то же самое - кидать, строить, красить, но для крыши ещё и свои свойства нужны - ведь она может ставиться только сверху других кубиков и только одна, больше ничего на шпиль крыши не поставить.
Получается, пирамидка должна делать что-то такое новое, что ей прям совсем нужно, а кубику вообще необязательно - а именно пирамидке нужно уникальное поведение - проверка, на кого её кладут: если это будет кубик - подходит, если там будет пирамидка - уже нельзя.
Можно это свойство добавить в объект кубика - но кубик может создавать экземпляры без этой проверки, это только пирамидке надо. Вот в этих случаях, чтобы не фаршировать ненужными свойствами готовые объекты мы применяем "наследование" - наследуем описание какого-то объекта и добавляем нужные свойства и методы или действия.
И вот мы создаём новый объект "Пирамидка", который такой же, как "Кубик", но имеет свой метод, который проверяет, участвует ли пирамидка в строительстве башни и если да - на какую фигуру она кладётся.
Можем ещё на этом примере докинуть SOLID:
1 не фаршируй кубик методами всуе, разделяй объекты, чтобы каждый содержал нужные ему свойства и поведения-методы;
2 если тебе нужен какой-то особенный кубик - создай новый объект, не вороши в уже созданных, ведь они - чертежы для экземпляров, их кто-то может использовать и поменяв что-то в этих чертежах - ты их подставишь делать не такие кубики;
3 если какая-то фигурка описана на основе кубика - она может иметь свои свойства и методы, но должна иметь все те же свойства и уметь всё то же, что имел и умел кубик; нарушение этого принципа ведёт к нарушению обратной совместимости, несёт смуту и непонятки - как это пирамидку можно окрасить краской, а кубик - нельзя? Если кубик можно покрасить - значит, и пирамидка должна уметь окрашиваться. Ведь все знают про кубики LEGO, но никто не знает про шарики - потому что шарик уже не будет крепиться и не будет иметь смысла как фигурка конструктора. Можно ли его выпускать? Можно. Но это уже не конструктор будет - что же ты из шариков построишь?)) Ничего)
4ый пункт про интерфейсы говорит: вот у нас был интерфейс "Кубикоподобное", он создавался, чтобы делать кубикоподобные детали. Потом мы добавили пирамидку, у которой есть свои методы. Так вот если мы хотим делать пирамидкоподобные детали - правильно для пирамидки создать свой интерфейс - "Пирамидкоподобное", а не добавлять новые штуки в "Кубикоподобное". Каждый новый объект если нуждается в описании - должен получать своё описание по своим свойствам и методам, лучше иметь 10 разных интерфейсов, написанных чётко для своих объектов, чем один интерфейс с целым списком свойств и методов, которые каждому объекту придётся проверять - а кубик ли он, а может, он пирамидка? нет? А может, он цылиндр?
Так делать нехорошо) Кубик должен проверять только описание для кубика, пирамидка для проверки должна иметь своё описание для пирамидки, это несёт иерархию и разделение объектов, а что толку иметь одно описание на все объекты? Это как когда вы заполняете большую форму на 20 пунктов и ошиблись в пункте адрес, нажимаете "Редактировать" - а вам все поля формы сбросило, нужно всё заново указывать - это нехорошо, каждое поле должно иметь свою кнопку "Редактировать (адрес)", которая будет отвечать только за своё поле.
5ый пункт - очень прост, он просит не привязываться к конкретным случаям и свойствам, а "мыслить ширше". Например, были у нас кубики, из глины делались, но у них оббивались грани - ну, теперь давайте делать кубики из дерева и не из дерева, добавим свойство "деревянный" для объекта Кубик и каждый экземпляр пусть указывает при создании - деревянный он или не деревянный.
Так делать нехорошо, нужно мыслить не категорией ремесленника, а проектировщика, мы должны зависеть не от дерево/не дерево, а мы должны учитывать материал будущего экземпляра. Поэтому мы добавили свойство "материал" - это - правильно и хорошо, и мы можем увидеть это хотя бы по тому бонусу, что никакие новые материалы не вызовут проблем и кубики из них можно будет прекрасно делать - хоть из стекла, а хоть из резины, да хоть из теста печь.
А вот если бы мы оставили свойство "деревянный" - "не деревянный", мы бы, во-первых, не знали бы, вот те экземпляры, которые "недеревянные" - окей, так а из чего же они там? Сахар? Пластилин? Из яблока вырезали? Мы бы знали только, что этот кубик - "недеревянный", а на все остальные случаи приходилось бы ещё какие-то проверки писать, чтобы узнать - из чего тот кубик.
Так что куда лучше сразу продумать и придумать абстрактные свойства, чем намертво завязываться на какие-то конкретные материалы или аттрибуты, даже для двух материалов это будет плохо работать ,так как у нас будут материалы из дерева и не из дерева и уже буквально для трёх материалов мы получаем кашу: у нас кубики из дерева, не из дерева из металла и не из дерева, не из металла. И опять же мы получаем то же самое - непонятку "не из дерева и не из металл" - так из чего он? И опять же следующим наследованным классам придётся добавлять методы и проверки - из чего ж там следующие придуманные кубики высекать решили.
Спасибо за подробнейшее пояснение. Подобное я читал давно у Троелсена, когда пытался изучить C# на относительно хорошем уровне. Сейчас мне уже 48, и если я вернусь в программирование, то буду максимум тупорылым джуном.
Дело не совсем в том, чтобы понять концепции ООП. Сами по себе они простые. А в том, чтобы научиться мыслить абстрактно, не являясь при этом в принципе "абстрактно мыслящим" человеком. Проблема в переносе знаний о кубиках и пирамидках на конкретные бизнес-задачи, которые перед тобой поставлены. Если ты к примеру делаешь, форму к БД - надо ли создавать классы, соответствующие предметам из этой БД, и все в таком духе. Я помню, когда пытался освоить эту тему, вопросы сыпались один за другим. И ответов я либо не слышал, либо слышал, но не понимал )))
Если ты к примеру делаешь, форму к БД - надо ли создавать классы, соответствующие предметам из этой БД, и все в таком духе.
Общепризнанного ответа на этот вопрос не существует.
Если ты к примеру делаешь, форму к БД - надо ли создавать классы, соответствующие предметам из этой БД
а тут с опытом приходит) неизбежно на первых порах у вас буду получаться классы-божественные объекты или наоборот - слишком много слишком атомарных классов. Но это не страшно, этим так-то многие популярные фреймворки грешат - где-то слишком много классов, прослоек и дроблений, чтобы максимально гибко можно было выстроить структуру, а где-то на одну строчку в дб - один класс со всем набором функций, которые могут понадобиться.
В общем, если хочется вынести какой-то айтем в класс - берите и смело выносите, так будет проще. Всё равно сразу грамотную иерархию классов не построить - но хотя бы вы получите прозрачную и понятную (хоть и, допустим, избыточную) структуру. С практикой будут приходить какие-то моменты, ну и хорошо бы где-то получать на работе проектную практику - смотреть как сделано, слушать от старших коллег, как делать, на крайняк спрашивать критики и чатГПТ
Что до тупорылого джуна - много проектов мечтают про таких, которые бы просто сидели и убирали рутину за мидлами/сениорами и чтобы это не надо было перепроверять как за ЧатГПТ или Copilot. И за это будут с удовольствием платиться деньги, вам будут выделять какое-то время, менторить, устраивать интернатуры, смотреть ваш код и предлагать вам смотреть куски чужого кода, разбираться, что там сделано и зачем. ИТ с удовольствием пожрёт любого адекватного человека в ряды свои. "Девки с дойками так и плачут по дембелю" - это про это) Много кто из джунов просто идут в ит "за бабками", минимально собираясь впускать в себя новый материал, для них это просто - работа за деньги. Я бы на вашем месте не переживал, а учился и пробовал, если есть возможность и желание (не знаю ваших жизненных обстоятельств).
Но уверенным 100% нужно быть. У меня тоже так бывало - в 32 пришёл в одну контору, где мне прямым текстом сказали "вы слишком старый быть джуном", это прямая цитата. И я у них спросил - а какая им разница, если меня устраивают стек, проект и ставка - "ну, вам у нас неловко будет, у нас одни молодые ребята". Ну ок, здесь не прокатило - наняли в другой компании, где был нужен джун.
Так что не переживайте из-за таких мелочей как излишество классов) Это как вы ещё авомобиль не купили, а переживаете, что гаража нету) Постепенно ешьте слона, по частям))
Была в свое время такая же проблема. Как тут выше сказал один мудрый человек «Тебе должно быть тесно в твоих знаниях». Я спокойно жил без ООП делая громадные монолиты. Мне казалось, что я понимаю как это работает, вот только зачем это нужно мне - вообще не понимал. Пока не возникла необходимость написать программу которая условно 16 окон на базе одного окна. Но при этом каждое окно должно отличаться от главного всего на 5%, но при этом работать независимо. Так же должна быть возможность редактировать настройки главного окна так чтобы изменения касались и остальных окон. Первой мыслью было нашарашить 16 функций и каждый раз корректировать все 16. Но что-то внутри восстало против такого подхода ))) и тут я вспомнил про ООП. Вообще, неплохо применить ООП в жизни помогает знакомство с Qt.
Понял ООП (в том виде в котором оно в C++ - не каноничном то есть) только прочитав как оно устроено внутри. То есть, прочитав про скрытый указатель на таблицу перегруженных методов и про сами методы, принимающие первым аргументом соответствующую структуру
Я для себя понял это как расширение типа. Вот есть у тебя int, char и т.д. Когда тебе этого недостаточно, создаёшь класс)))
Но большинство сейчас используют объекты направо и налево. Чисто ради удобства, не считаясь с памятью.
Могу ошибаться. Но объекты сейчас часто используют просто для группировки данных.
На самом деле не вы одни.
Я и сейчас иногда испытываю трудности с декомпозицией. Впрочем это не проблема ООП, это проблема архитектуры, просто люди этого не понимают.
Но самое вредное, это то, что люди считают важным наследование, полиморфизм и интерфейсы. Это просто кластердэмэдж, как говорить, что автомобиль - это колеса прикрепленные к кузову. Это инструменты, которые используются, но не характерны для ООП.
Основное в ООП это организация кода в иерархию классов, где данные связаны с методами обработки. Причем иерархия - не про наследование, а про зависимости. Наследование не обязательно.
И в эту минуту я чувствую как начинают шевелиться волосы на моей голове. От шока, что не понимаю, что это такое.
С подобным столкнулся, вероятно, на первом курсе. Препод по матану резво вещает что-то вроде "ну, это элементарно и очевидно, поэтому у нас получается вот так-то и так-то".
А мне вот это всё совершенно неочевидно, поскольку в школе какие-то вещи (элементарные) или не проходили вовсе, или весьма поверхностно.
В программировании есть вещи для меня сначала неочевидные совершенно, но когда разберёшься, это действительно оказывается элементарно (очевидно\логично).
Касательно пособий "с нуля и быстро научить чему-то-там-вообще-любому". Вот именно, что ежели я ничего не понимаю, начинать нужно с азов, объясняя прям как для тупых.
Препод по матану резво вещает что-то вроде "ну, это элементарно и очевидно, поэтому у нас получается вот так-то и так-то".
У нас также было. И когда преподаватель понял это, что в группе его объяснения очевидны дай бог 1-2 людям, он просто махнул рукой на нас, даже не попытавшись нас ничему научить. Открыто сказал, вам это не нужно. Это было на одном из первых занятий на первом курсе.
Я тогда знатно прифигел от такой прямоты и пофигизма. И да, как жизнь показала, он был не прав. И зря кушал свой хлеб, при таком отношении к студентам, пусть даже слабым.
И далее, по цепочке, знакомые всем мысли о собственной непригодности.
Мысли безусловно верные. Потому, что есть более базовые вещи чем программирование, и их тоже нужно понимать.
Нет такого нуля с которого можно гарантированно учить - всегда найдётся представитель отрицательных значений. Для учащегося это означает выбор - либо быть готовым отвлечься и что-то выяснить по ходу чтения, либо тратить время в пустую на пережёвывание жёванного - перечитывать уже известное. Сколько времени нужно чтобы выяснить чем Int16 отличается от Int32? Правильно, 5 минут вместе с мытьём рук перед прикосновением к планшету, всё описано тысячи раз. Вы даже не пытались - непригодны.
То же самое можно выяснить экспериментально - комп то есть. Так можно разобраться с чем угодно, в смысле такого подхода достаточно, но метод точно не универсальный. Но другого позволяющего пробить всё- нету. Кто не пробовал - непригоден.
Нетривиальную тему практически невозможно разложить в линейную последовательность. Поэтому 100% понимания по ходу чтения книги недостижимы, приходится прочитать всё и только после этого смотреть есть ли непонятое. В старину все европейцы учились этому на высоком уровне сталкиваясь с Библией, сейчас нет - оказателям образовательных услуг выгодно строить маркетинг вокруг химеры линейного обучения. Вы хотите линейности - непригодны.
Вам кажется что поняв разницу между между двумя age в this.age = age вы вкатились, ведь теперь тоже можете писать такое. Отнюдь, это знание отличает дрессированную обезьяну от
простонароднойдикой. Чтобы реально вкатиться, нужно понять, какую задачу решал человек и почему он решил её именно так, this.age не есть Природа, это люди придумали. Довольствуетесь минимальным уровнем - непригодны.Вы считаете что преподаватели нуждаются в подсказках? Они нуждаются в деньгах, поэтому подавляющее большинство книг и курсов - мусор. Более того, я пока не встречал более агрессивной среды чем IT - самый подлый маркетинг, самое наглое враньё, самая откровенная манипуляция, борьба технологий без берегов. Житель страны розовых пони - непригоден.
На сколько серьёзная проблема - быть непригодным? В любой области, кстати.
Топчик типа cream of the cream Вам заказан, этого не достичь никогда. Ещё раз: НИ-КО-ГДА. Но дико подавляющее большинство тоже никогда не войдёт в топчик, невелико огорчение.
Любая Ваша первая реакция всегда будет с большой вероятностью неверной. К этому просто можно привыкнуть и подождать второй. Единственно где такое критично - это когда требуется молниеносная реакция. Такое можно устроить на собеседовании и гарантированно посадить, не зависимо от реального уровня кандидата, но тот, кто на это способен, никогда таким не займётся - умён слишком. Максимум - сначала посадит, а потом возьмёт.
Кто виноват? Виноват печальный факт что мышление определяется структурой мозга, а эта структура практически завершает формирование годам к четырнадцати. Поэтому раньше интересовались - из какой он/она семьи. Да и теперь в некоторых кругах…
Что делать? С первопричиной ничего не поделаешь, значит нужно играть теми картами которые есть. Не упуская из виду причины непригодности, начинаем учиться программированию. Сами, только сами, книги и, чем чёрт не шутит, курсы - только тогда, когда сами поняли зачем и почему.
Тут нужно добавить ещё одну засаду до которой в статье не добрались - основы. С одной стороны, они есть - программа работает на ОС, ОС на компьютере, компьютер на прерываниях, прерывания на транзисторах, транзисторы на электричестве… а с другой - их нет, практически всё в IT - реализация замысла, при этом то, что считается продвинутым, существовало изначально и влияло на то, что считается основами. На замысел влияли идеи общего характера, но их стараются избегать.
Начинать с основ которых нет - спорно. Начинать с переменных? Почему не со значений, операторов, выражений, функций, классов, замыканий? Можно построить курс по тому же JavaScript так, что сама идея что значение переменной может изменяться, будет весьма продвинутой и в самом конце…
Начинать с основ - опасно, поскольку в какой-то момент можно остановиться не узнав о существовании много, а утверждение о существовании - второе по силе (первое - он несуществовании). Можно ли написать полезный (в плане подготовки к работе по найму) курс JavaScript не коснувшись понятия prototype? Да легко…
Кто не понял что делать вместо начинания с основ - читайте внимательнее, выше уже написано. Итерациями изучать сразу всё.
Как выучить Python? Прочитать FAQ, станет понятно общее положение дел, либо станет интересно, либо желание это учить отпадёт. Прочитать спецификацию. Уточнить наиболее интересные места - Python есть на всех устройствах. Если Python не выучен, вернуться к чтению спецификации.
Как выучить Rust? На сайте написано - read the book. То есть так же, как Python, только вместо одной спецификации будут минимум три - на Rust, Cargo и Rustc. И потребуется что-то более компьютерное чем iPad, хотя бы Андроид смартфон с Termux. Поэтому учить Rust первым сложнее чем после Python.
С чего начать? Я бы, отталкиваясь от двух предыдущих параграфов, выучил бы что попроще, но требующее тех же методов. Нормально выучил, до перехода от классики «я знаю что я ничего не знаю» к, как минимум, знанию того, чего именно я не знаю и где оно описано.
Например, то, что описано через man. Ключевые навыки те же - быстро прочитать всё, запомнить координаты, и разложить, при помощи клавиатуры конечно, на интересное, нужное и отнюдь. Хорошие кандидаты - bash, tmux, helix. Наверно можно и VS Code или neovim.
Помогают ли книги? Да. Как сказал однажды в интервью Пол Маккартни - не всё говно. Но смотреть надо скорее не на то, чему учат, сколько на «почему» и «зачем». Иногда - на порядок изложения, по хорошей книге понятно как и до каких пределов можно линеаризовать. Помню, но не название, как в книге по Rust автор переключался с cargo и toml на rust и обратно, очень поучительно.
Помогают ли курсы? Да. Но косвенно - через общение с преподователем и соратниками, сплетни, налаживание контактов… При хорошем преподавателе - через его отношение и образ мысли. Стоит ли это своих денег - функция от их количества.
Исполнено на iPad под Новый Год и под спящей кошкой. Она уже облизывается, беру пример с Шахразады.
Сами, только сами, книги и, чем чёрт не шутит, курсы - только тогда, когда сами поняли зачем и почему.
Как выучить Rust? На сайте написано - read the book.
Нет ли здесь противоречия? Вы вначале пишете, что книги - только тогда, когда сами поняли. И через несколько строк пишете, что начинать изучение языка программирование надо с того, что почесть книгу.
Про "когда сами всё поняли" - это к курсом относится, не к книгам.
Кабы определённые понятия были мною постигнуты лучше за меньшим вызываемым таковыми отвращением, я бы написал, что противоречия нет ибо есть диалектическое единство…
Любой текст можно назвать книгой. Но тогда некоторые книги будут особенными, как The Book.
На странице Learn Rust исчерпывающе указано что нужно знать чтобы знать про Rust всё, с точки зрения пользователя. Всего 15 пунктов из которых нужно изучить 13, поскольку из первых трёх, в число которых входит и книга, нужно выбрать один. То есть “read the book” - немного лукавство, и я как-то не припомню другую книгу которая вот так, без зазоров, входила бы в полную документацию.
Кстати, можно прочитать The Book, или выбрать одну из двух альтернатив, и потом прочитать The Reference, а можно вместо этого прочитать The Reference дважды или трижды на разном уровне внимания и глубины.
Стоит ли потом, скажем прочитав The Book по диагонали, читать скажем Programming with Rust? Опционально, мне зашли и манера изложения и стиль автора, но интерес - в его отношении к предмету (это у него опыт с Rust, а не у меня). Но узнавать из неё про функции и переменные - увольте…
Кто виноват? Виноват печальный факт что мышление определяется структурой мозга, а эта структура практически завершает формирование годам к четырнадцати. Поэтому раньше интересовались - из какой он/она семьи. Да и теперь в некоторых кругах…
Ваши данные несколько устарели. Уже доказана пластичность мозга. Причем пределы пластичности почти неограниченны. При повреждении части мозга, остальные части могут даже перераспределить функции между собой.
Но необязательно себе мозг повреждать для перестройки))) Можно банально переучиться. Причем практика имеет первичное значение. Так исследования лондонских таксистов показали, что у них значительно меняется размер гипокампа, отвечающего за пространственную память, спустя несколько лет работы в такси. Ссылку не могу приложить, загуглите если интересно.
Другое дело, что это долгий процесс. Например, чтобы научится той же математике - придется уделить этому сколько-то лет, чтобы мышление развить и знания закрепить. От интенсивности занятий зависит. Таксисты целыми днями ездят, и тут также - будешь постоянно математикой заниматься, не заметишь как сильно прокачаешься.
А ещё есть такой фактор как старость. Мозг со временем стареет, становится менее эффективным. Не критично, но разница есть. Влияет на скорость обучения и качество запоминания.
Зато с возрастом мозг легче сложные концепции понимает. Молодым это даётся куда труднее. Поэтому ухудшение скорости мышления и памяти немного компенсируется лучшим пониманием материала.
Но интересоваться из какой семьи все равно надо. Ведь помимо знаний, навыков и прочего - есть ещё и воспитание. Мало кто во взрослом состоянии способен скорректировать свое воспитание. Это очень тяжело. Тяжелее, чем изучить математику уровня кандидата наук. Ведь это стержень. Это долгие годы с психологом прорабатывать.
Например, эмоции и управление ими - мы впитываем их от нашего окружения с младенчества. Отчасти поэтому у детдомовцев (те что с младенчества) бывают проблемы с социализацией. Тепло, улыбки, смех, обида, страх и т.д. - все закладывается с первых дней жизни. Когда младенец улыбается - это он вас копирует. Он ещё не понимает, что это, но активно учится этому. Изучает вашу реакцию на улыбку. В общем, запоминает все эмоции, что вы демонстрируете. И сразу же практикует. Запоминает обратные реакции. Поэтому, чем здоровей семья, тем больше шансов на какой-то успех в жизни у потомства.
Эмоции будут либо помогать, либо мешать вам добиваться целей.
И ведь многим людям они реально мешают. И это подарили им их родители (на 40%) + социализация до 14 лет (на 40%). Остальные 20% могут меняться по жизни. Может и больше. Зависит от испытаний в жизни. Например, война сильно меняет людей.
А воспитание потом уже напрямую влияет на достижения. Вот для чего надо на семью смотреть)) Но надо помнить, что это лишь один факторов воспитания, не единственный. Люди очень сложные биологические машины. На наше программирование влияет буквально все. От врождённых способностей, семьи, друзей, школы и т.п. до обстановки в стране, где живём.
P.s. Надеюсь, своим сообщением я дал надежду всем, кто хочет изучать новое. Дерзайте, у вас есть все шансы! С Наступающим!
нередко преподаватели программирования не замечают и не осознают, что новички, которые раньше действительно не программировали, реально не понимают ряд вещей, которые людям с опытом кажутся сами собой разумеющимися.
Да, это так. В свое время когда наткнулся на сочетание "3D" долго нигде не мог найти что это такое ) То же самое с "регистр". А еще раньше с "файл" )))
"Однажды, в ходе очередной попытки освоить программирование, мне попалась..."
... Вакансия с кучей ежемесячного бабла, что, для полувекового меня (возраст 50+), послужило стимулом вката вайти. Вбросил кучу бабла на очные курсы (всего их было шесть: один - семимесячный, второй - шестимесячный, остальные четыре - трех-четырехмесячные), параллельно - три очных курса трёх месячных курсов по английскому)...
С высоты далеко за 55+ понял, что куча непоняток, росших как грибы - это не стоит тех денег, за которые попытался войти вайти)
ЗЫ: зато (из контекста темы "У кого что болит, тот о том и говорит") - нет непоняток с вентиляцией лёгких, с разворотом бедра и использовании еловых шишек при мае-гири в киушине, так непонятно описанных в самиздатах)
ЗЗЫ: ради коммента вспомнил пароль и зашёл в хабр в этом, уходящем 2024 году)
В 10 лет появился первый компьютер "Партнер 0101". В инструкции было много непонятного. Например, оператор. Один передает что-то другому. А я сам - один. Ну отец еще вечером мб придет, но откуда ему знать такое, даже спрашивать глупо. А в инструкции операторов-то больше двух!! Вот проблема...
Как почти всегда, комменты интереснее статьи( ничуть не принижаю автора, просто в комментах все более развёрнуто, интересно и познавательно). Так что чем больше тут написано комментов, тем меньше будет непоняток в программировании. Пишите что вам было не понятно и как вы с этим справились, ну или не справились. Это будет отличное пособие для тех, кто только хочет начать изучать программирование или на первых этапах
Пишите, Шуры, пишите!
Итак, небольшая коллекция того, что бывает непонятно изучающим программирование
тю! неожиданно.
я думал что автор статьи не просто классифицирует, но и даст определения.
PS: в советские времена одна и та же Физика, например (учебник Пёрышкина, если кто помнит) в школе изучалась дважды.
Сперва законы Ньютона (и прочие) рассматривались в формулировках, понятных шестикласнику: вместо "сила" говорили "тело действует", понятия вроде "система отсчёта" вовсе опускались и так далее.
И в таком ракурсе с понятиями физики мог разобраться вчерашний пятикласник, два-три года назад выучившийся писать и читать. Напомню, вопросом "учить читать и писать" тогда занимались не до школы, а в школе.
Увы, в современное время учебники Пёрышкина заменили на учебники другого Пёрышкина (который не имеет отношения к коассику). Ну и этот подход "сперва формулировать простыми словами, а уж потом..." оказался забыт.
А ведь именно он хорошо бы работал как раз в отношении новичков.
Отличное ессе. Расскажу, что со мной как то произошло, хоть и не по теме. Как-то, я хотел научится играть на гитаре. Купил гитару, по тем временам, за 600р.. И купил книгу "Самоучитель МАСТЕРА игры на гитаре". Кстати, за 700р. С диском. И начал делать все, что там написано, шаг за шагом. В начале там рассказывалось, что гитару надо настроить, и я пытался это сделать. Крутил "колок", чтобы получить 440 Гц, но сил пальцев стало не хватать. Тогда я взял плоскогубцы и начал крутить ими. Мой друг, который при этом присутствовал, заметил, что "патрубок гнется!". Да, это мы с ним сейчас знаем, что это называется "гриф", но тогда называли это "патрубок". Вообщем, гитара согнулась как лук для стрельбы, а потом, с огромным грохотом лопнула струна, и я "получил по рукам". Какая мораль? Я специально проверил, изучил ВСЮ книгу, вдоль и поперек. НИГДЕ в книге не упоминается какая струна первая...
П.С. Сносно играть, я таки, научился.
Поддержу. Лет в 8-10 пробовал учиться играть по самоучителю. Очень многое было непонятно и из теории и из практики. Отец привёл действующего музыканта, и он на пальцах (буквально) показал, как надо. Сам бы я ни в жизнь не догадался.
А как транспонировать ноты на бумаге понял только, когда мне это (опять же на пальцах) объяснил преподаватель музыки.
Мораль: самоучители для гениев-вундеркиндов.
P.S. А поводу струны, какая первая, ну, это же очевидно, не правда ли? # sarcasm
патрубок? хотелось бы это видеть (я про "лук") :)
мне то проще было: гитару дядя настраивал.
а я купил струны-двенадцатку и попробовал настроить их на гитаре в строй для девятки. Гитару жалко...
Но ведь «ля» первой октавы находится на 5 струне...
Самая яркая в моей практике иллюстрация разницы мышления программистов и не-программистов. Из диалога с дочерью (не дура, победительница олимпиад по математике):
— Ты почему этой переменной значение не присвоила, откуда программа будет знать, что там должно быть?
— Как откуда?! Это же очевидно!
Уже лет 20 в ИТ, лет 10 в системной аналитике, но до сих пор потряхивает от использования в примерах foo и bar. Как же это обескураживало поначалу.
Сын школьник учил Python по гос программе, в итоге разбирал с ним все лекции и задачи. ИМХО питон (равно как и js) не лучший выбор для обучения программированию. Основная проблема - нет должного фокуса на концепции типов данных. Ну и пример простой ввод данных с клавиатуры map(int, input().split()) воспринимается как некая магия, потому как у обучаемого нет понимания преобразования типов, функций и их параметров, объектов, сложных типов данных и передачи функции как параметра в map. В итоге чтобы понять как работает ввод с клавиатуры трех чисел через пробел нужно освоить весь курс, и до кучи следующий где основы ООП дают.
простой ввод данных с клавиатуры map(int, input().split())
За подобные вещи нужно бить клавиатурой по пальцам. Да, так короче. Но не читаемо и неизменяемо. Это забавный трюк, применимый в ровно одном случае, вот и всё.
Плюсую. В нормальных учебниках должны писать ровно одну строку на одно действие с подробным комментарием, чего тут вообще происходит (в строке).
Примерно так:
# Получаем от пользователя некие данные (в виде строки):
user_input = input("Введите несколько чисел, через пробел")
# user_input == "10 22 55"
# Так как мы получили строку, разделяем её на отдельные переменные:
user_digits = user_input.split(" ") # Разделяем строку по указанному символу (пробелу)
# user_digits == ["10", "22", "55"]
# Окей, данные разделены, но это строки из знаков, а не числа (int). Преобразуем их в числа:
integers = map(int, user_digits)
# integers == [10, 22, 55]
# делаем что-то с этими числами...
print("Вы ввели:", integers)
На данном этапе даже не обязательно объяснять, что map может принимать первым аргументом вообще любую функцию, хватит и пояснения "вместо Int можно использовать float/double/bool".
Ну или использовать вместо map - for loop, но тогда код будет больше, а пояснений потребуется не сильно меньше...
Map вообще функция высшего порядка, а int является методом парсинга и может быть спутан с типом (хотя с типами еще более печально, питон же)
Лучше было бы использовать цикл - проходим по списку и преобразуем строку в число.
И только когда ученик это освоить, показать, как можно типичные циклы агрегировать.
Да питон не простой язык. Очень своеобразный. Это изначально "а=5" , а дальше куча своих особенностей. Лучше с Си начать, и как память устроена, ссылки, указатели понять.
потряхивает от использования в примерах foo и bar
То же самое. Очень странно, что их применяют, ведь по сути это как магическое число.
Основная проблема в том что все жалуются на паскаль или си в школе или вузе. Потом "продвинутые" преподы по всяким js,python,swift и подкладывают свинью. Просто перестали изучать преобразование типов, битовые операции, арифметику с дробями и т.д.
Дано(псевдокод)
переменные a и b это допустимый пользовательский ввод var a = 30
var b = -1.3
var d = a&b
так чему должно быть равно d и в каком языке??
Проблема в том, что простота этих языков на самом деле берется путем многих умолчаний и скрытого поведения. Типов нет, но типы есть.
Как итог имеем громадную проблему скрытых абстракций при любом шаге влево-вправо.
Один раз встречал такую дичь: (где-то в первых главах книги) и вот сейчас мы переходим в наш Emacs.
Это статья - шутка?
Если нет, то начинать с "Код" Петцольда и продолжать какой детской книгой по АЛГОРИТМИКЕ, потом можно "... и структуры данных" Вирта и параллельно курс программирования MIT (как по мне, старый, с примерами на Scheme, лучше).
И только потом int16, avx и прочие ЧАСТНОСТИ. Ну или начинать наоборот, с ассемблера и мшкода, но это после первых двух шагов, когда написать русским псевдокодом или блок схемой алгоритм решения Ханойской башни уже можешь.
Как то получилось, что лет в 10 я уже освоил мультивибратор, в 11 - понимал, как работают базовые элементы цифровой логики, в 12 подружился с триггерами, а в 13 уже отчетливо представлял себе что такое сумматор и сдвиговый регистр. Поэтому уже в 14 освоил программирование на ассемблере i8080 и MCS-48.
Не могу утверждать, что это единственный правильный путь, но эти знания мне в программировании помогают до сих пор.
Может всё же подобная база была бы полезна при обучении программированию?
Не могу утверждать, что это единственный правильный путь
Если речь о понимании того, что вы на самом деле делаете, когда используете тот или иной язык программирования, - это таки единственно правильный путь. Нет царского пути в геометрию.
Ну пожалуй не все из этого, а некий рафинад.
Но да, многое было бы понятно.
На самом деле это всё не так уж страшно. Если не уходить глубоко в физику, действительно существенную только для аналоговых схем или для технологов и схемотехников, то это не такой уж большой объем.
Я специально опустил, что уже учась в МИЭТ мне пришлось для курсовика разрабатывать и создавать свою простейшую планарную микросхему. Самый ад был в химлаборатории во время фотолитографии и травления. Так же пришлось помучиться с расчетом ОУ для аналоговой обработки сигналов с ФАР перед АЦП. Вот это, на мой взгляд, было уже излишеством в учебном процессе.
Начинал изучать python сразу с pandas (на курсах онлайн разумеется). Ох, и намучался... Пока не прочитал какое-то количество книг, где объясняется, как у питона внутри всё устроено...
4. Возвращаемое значение
“… на первых порах … никак не мог въехать в "возвращаемое значение". Хорошо помню как это раздражало в очередном тьюториале - "кто возвращает", "куда" и главное "зачем". Сейчас конечно смешно, но тогда это выглядело не то, что "магия", а какой-то мировой заговор преподавателей, которые твердят одно и то же, но не хотят объяснить толком что это такое”.
Я до сих пор не до конца понимаю что это значит. Ожидал разъяснения какого-то разъяснения, но оказалось, что формат статьи не такой... Может хотя бы кто-то из комментаторов объяснит?
Тут по-хорошему надо с определения функции начинать. Тема на час примерно.
Функция чего-то считает, а потом вам выдает ("возвращает") результат. И вы сами решаете, что именно она вам выдает.
функция (а,б=значения, к=результат)
с=а+б
если с больше 0, то к="число положительное"
если с меньше 0, то к="число отрицательное"
результат=к
Ну если вам понятна концепция переменных, то вы знаете, что такое присвоение
a = 3 // присваиваем переменной А значение 3
b = 5 + 7 // присваиваем переменной B значение, равное сумме 5 и 7
c = input("введите в консоль число") // присваиваем переменной C значение, которое пользователь ввел в консоль
d = pow(2, 2) // присваиваем возведение в степень
Здесь кроме первого примера мы вызываем функции, которые "возвращают" значение, чтобы мы присвоили их переменным. Очевидно, что сначала нужно посчитать результат 5+7 прежде чем мы присвоим его переменной B (положим в это место памяти)
Когда вы описываете свою функцию, вам нужно описать какой будет ее результат, что вернуть пользователю. Это и есть "возвращаемое значение"
К примеру, функция, которая принимает имя пользователя и возвращает строку приветствия:// тут мы описываем функцию, ее результат и входной параметр
string CreateGreetings(string userName)
{
// делаем полезное действие
string greeting = "Привет, " + userName + "!";
// возвращаем результат, то самое возвращаемое значение
return greeting;
}
// использование функции
string greetings = CreateGreetings("Петя");
// входной параметр - петя, выходной - наше приветствие
Console.WriteLine(greetings); // выведет "Привет, Петя!"
Я до сих пор не до конца понимаю что это значит. Ожидал разъяснения какого-то разъяснения, но оказалось, что формат статьи не такой... Может хотя бы кто-то из комментаторов объяснит?
Что такое "возвращаемое значение"? Если кратко, то это значение, которое возвращает функция.
Особенность возвращаемого значения состоит в том, что его можно присвоить в другую переменную.
Некоторые функции возвращают значение, некоторые не возвращают.
Признаком того, что функция возвращает значение является указание на это после круглых скобок с параметрами функции.
Пример, как это выглядит в Swift:
func sum (a: Int, b: Int) -> Int {
var с = a + b
return c
}
В этом примере мы объявляем функцию с названием sum.
В круглых скобках - параметры функции, где указаны входные параметры. Т.е., мы получаем значения, которые будут использоваться в расчетах.
После круглых скобок идет стрелка и указание типа: -> Int. Это и есть обозначение того, что данная функция возвращает значение. Если такой стрелки нет, то функция значения не возвращает.
Также внутри, в фигурных скобках в теле функции дополнительно используется слово return, которое тоже показывает, что данная функция возвращает значение.
Как происходит возврат значения? - Мы объявляем новую переменную и присваиваем ей значение из функции, как результат некой операции, которую функцию выполнила.
var d = sum(a: 5, b: 3)
В итоге, переменная d теперь хранит значение 8, которое ей вернула функция sum.
Если же, в объявлении данной функции не указано -> Int, то она ничего не возвращает и, соответственно, ничего присвоить в другую переменную мы не можем.
Объяснить, что такое "возвращаемое значение" можно с двух сторон, используя две разные модели. В любом случае, ответом на вопрос "кто возвращает" будет "функция".
Можно провести аналогию со школьной математикой, где функции задаются либо таблично, либо формулами. Там возвращаемое значение - элемент из области значений функции. Пусть f(x)=sin(x)/x, тогда f(1.57) "вернёт" примерно 0.64. "Куда возвращает" - в место использования; если у нас есть формула f(1.57)*2+1, то в ней мы можем заменить f(1.57) на 0.64, произведя вычисления согласно определению f. Ответ на вопрос "зачем" как всегда самый сложный. Функция f: A -> B позволяет нам абстрагироваться от конкретного способа связи элементов A с элементами B. Возвращая значение (элемент из B), мы выполняем обратную операцию для некоторого частного случая (элемента из A).
Подстановка f в выражение
Пусть f(x)=3*x.
Вычислим значение выражения f(5)+1.
--
f(5) + 1 =
= (3*5) + 1 = то, что в скобках "вернула" нам f
= 15 + 1 =
= 16
Можно привести пример конкретного calling convention. Вызванная функция ожидает, что в непрерывном куске памяти (на начало который указывает один из регистров) находятся её аргументы, перед которыми записан адрес той инструкции, с которой будет продолжаться выполнение (адрес возврата - "куда возвращает"), когда функция выполнит свою работу. Одним из эффектов работы функции может быть изменение регистра возвращаемого значения, которое ожидается в месте возврата. "Зачем" - чтобы передать в место вызова явный результат проделанной работы.
Процесор i386, соглашение cdecl
; У нас есть две функции. main вызывает triple, которая возвращает
; утроенное значение своего целого аргуметна.
; main вызывает triple от 5 и увеличивает результат на 1.
main:
; Положим число 5 на стек.
push 5
; Теперь регистр ESP указывает на место в памяти, где лежит
; число 5. Например, ESP=0xff8113f8, а по адресу
; 0xff8113f8 лежат биты 00000101 00000000 00000000 00000000
; Вызываем функцию triple.
call triple
; Перед вызовом call положит на стек адрес инструкции,
; следующей за call. Это сдвинет ESP на 4 вниз, и запишет
; адрес возврата по адресу, соответствующему новому значению
; ESP. Если следовать предыдущему примеру, а адрес инструкции
; call (строка 12) равен 0xf7ee0240 то теперь
; ESP=0xff8113f4, а по адресу 0xff8113f4 лежат биты
; 11110111 11101110 00000010 01000101 00000101 00000000 00000000 00000000
; Вот в это место произойдёт возврат из triple, когда оттуда
; сделают ret (строка 48). И сейчас в EAX лежит число 15, то есть
; утроенное значение 5. Осталось увеличить EAX на 1.
inc eax
; EAX=16. Теперь вызовем отладчик в демонстративных целях:
int3
; и завершим работу программы.
ret
triple:
; Прочитаем аргумент из стека в регистр EAX.
mov eax, [esp+4]
; Скопируем его значение в EDX.
mov edx, eax
; Удвоим EDX.
add edx, edx
; И сложим наш аргумент с его удвоенной копией.
add eax, edx
; Готово, теперь в EAX лежит утроенное знечение. Работа
; завершена, можно возвращаться в место вызова.
ret
; Что сделает ret? Прочитает то, что лежит по адресу,
; на который указывает ESP, и вернёт нас по нему (обратно),
; одновременно увеличив ESP на 4.
В данном примере машина выполнит инструкции в следующем порядке (укзааны номера строк) - 7, 13, 35, 38, 41, 44, 48, 25, 28, 31.
Для контроля понимания можно посчитать на бумажке результат рекурсивной функции, используя обе модели. Например из определения "f(0)=0, f(1)=1, f(n)=f(n-1)+f(n-2)" получить значение для f(10) - тут должно получиться 55.
Возможно для наглядности стоит сделать какую-нибудь анимацию, как происходит вызов, передача аргументов и возврат значения.
Ключевая ошибка в глупых и безнадежных попытках освоить навык путем чтения книжек/статей/просмотра видосов/етц. (и в уверенности в том, что это в принципе возможно).
Сколько бы человек ни читал и ни изучал способы пожать от груди сотку - он не пожмет от груди сотку. Единственный способ пожать сотку - это идти в зал и тягать штангу.
Это верно, но даже штангу тягать надо с пониманием.
Но если ничего не прочитав и не посмотрев пойти в зал тягать штангу, то есть высокая вероятность, что что-нибудь отвалится. От груди это правда посложнее, со становой вот как раз плюнуть. Поэтому всё таки сначала теория, потом практика.
Ну не скажи, книги для того и сделаны, чтобы ты прочитал то, чего сам не знал, и узнал это.
И это просто работает
Другое дело что книги не совершенны и не могут решить все и всегда. К примеру иногда уровень должен быть достаточным для чтения книги.
Прочитав книгу, можно узнать, как играть на гитаре, но нельзя научиться играть на гитаре.
Люди верят в существование какого-то магического объяснения, которое бац! И запишет им в голову навык, как Нео навык кун-фу. Но в реальном мире, а не в матрице, это не работает. Надо прикладывать усилия - много, долго и упорно.
Только вот если людям честно говорить, что для освоения базовых навыков программирования требуется несколько лет фуллтайм обучения - ни кто на курсы записываться не будет.
Что такое переменная, не знают даже авторы стандарта языка Си. В одном месте написано, что это поименованная область памяти, а в другом - что значение, привязанное к имени. Хотя это две разные вещи.
В теории принято считать, что переменная - это значение, связанное с именем. Не наоборот.
Занимаюсь иногда репетиторством со студентами, очень много приходится объяснять такие базовые вещи, которые преподаватели пропускают.
Например:
Что компилятор обычно генерирует машинный код, а не ассемблерную программу.
Что логические && и || не являются функциями, и в чём отличие.
Что параметры в макроопределения передаются по имени, и в чём отличие от передачи по значению и по ссылке.
В каких случаях рекурсия эквивалентна циклу, а в каких нет.
В чём вообще смысл рекурсивного вызова.
Чем операционная семантика отличается от денотационной, и они обе - от синтаксиса.
Как в точности выполняются операторы цикла (особенно в языках, где существуют сложные формы).
Почему вообще программа записывается в виде структурных операторов с отступами.
В чём смысл передачи параметров, чем отличатся формальный параметр от фактического и чем нормальный порядок вычислений отличается от аппликативного (кстати, во многих книгах по программированию передача параметров объясняется через нормальный порядок, хотя он в обычных языках аппликативный).
Что конкретно делает оператор описания переменной (в языках со статической и динамической типизацией).
Что конкретно делает оператор присваивания (в языках со статической и динамической типизацией).
Чем инициализация переменной отличается от присваивания (в языках, где отличается).
Чем исполняемые операторы отличаются от неисполняемых.
И т.д.
компилятор обычно генерирует машинный код, а не ассемблерную программу
Как Вы махом все компиляторы LLVM отнесли к необычным.
LLVM не генерирует ассемблерную программу в качестве промежуточного этапа к машинному коду.
Некоторые авторы называют IR ассемблером, но это неверно.
компилятор обычно генерирует машинный код
Называть можно по разному, но как Вы, называть IR машинным кодом уж точно некорректно.
Ну и в довесок, тот же GCC замечательно генерирует ассемблерную программу, если его об этом попросить.
Я вполне могу согласиться с утверждением, что компиляторы обычно не генерируют ассемблерную программу. Но я не согласен с утверждением, что компиляторы обычно генерируют машинный код.
Результатом работы как llvm, так и gcc, является объектный файл с машинным кодом, который никогда перед этим не был ассемблерной программой. Что не отменяет возможности выдачи также ассемблерной программы по запросу.
Что касается IR, то это вполне обычная внутренняя форма машинно-независимого представления программы в компиляторе, по сути те же тетрады, применяющиеся в компиляторах с 1960-х годов.
Результатом работы компилятора LLVM является IR код, который не является машинным кодом, а лишь промежуточным кодом независимым от платформы.
Объектный файл с машинным кодом формируется уже не компилятором, а соответствующим целевой архитектуре бекэндом.
Впрочем, раз именно Вы взялись утверждать, что IR является машинным кодом, то можете привести доказательства, ссылаясь на авторитетные источники информации.
Еще раз, я не оспариваю, что компиляторы обычно не генерируют ассемблерную программу. Но я не согласен с утверждением, что компиляторы обычно генерируют машинный код. Они вполне могут генерировать промежуточный код, не являющийся машинным.
Бекэнд является частью компилятора.
Я не утверждал, что IR является машинным кодом. IR вообще не является результатом работы компилятора, это промежуточное представление.
Бекэнд является частью компилятора.
В структуре LLVM это совершенно независимые вещи. Например: "The Clang project provides a language front-end and tooling infrastructure for languages in the C language family (C, C++, Objective C/C++, OpenCL, and CUDA) for the LLVM project"
Будете это оспаривать?
Проект clang, рассматриваемый как исходный код, является фронтендом компилятора в структуре llvm. Но любой конкретный компилятор на его основе (т.е., условно говоря, clang.exe) состоит из фронтенда clang, оптимизатора llvm и бекенда для целевой архитектуры. На входе этот компилятор имеет исходные модули на C/C++, а на выходе - объектные в машинном коде.
Фронтенд почти не зависит от бекенда в структуре llvm, но, тем не менее, они являются частями одного и того же компилятора.
бекэнда для целевой архитектуры
И даже это не обязательно. Никто не запрещает использовать KaleidoscopeJIT
они являются частями одного и того же компилятора.
Докажите. Сколько не видел компиляторов LLVM - это совершенно отдельные проекты. Покажите хотя бы один компилятор LLVM на github, который содержит кодогенератор.
Компилятор - это конкретная программа, выполняющая функцию компиляции, а не проект на гитхабе.
Покажите мне, как вы пользуетесь компилятором, не содержащим функцию кодогенерации.
Компилятор - это конкретная программа, выполняющая функцию компиляции
Но не в терминологии LLVM. Может хватит догм? Я уже который раз даю ссылки на первоисточник, а Вы не предоставили пока ни одной.
Покажите мне, как вы пользуетесь компилятором, не содержащим функцию кодогенерации.
Например в ClangJIT кодогенерация происходит только при исполнении программы средствами KaleidoscopeJIT.
Я уже молчу про компиляторы .NET, которые компилируют в код CLR, который тоже не является машинным.
Думаю, вас не очень затруднит подняться по ветке вверх и вспомнить утверждение, с которым вы взялись спорить? Но я могу и напомнить:
Что компилятор обычно генерирует машинный код, а не ассемблерную программу.
Каким образом ваши доводы про KaleidoscopeJIT его опровергают?
Что касается первоисточников, то, если у Вас возникают сомнения (что странно при Вашем опыте), то наберите в Гугле что-нибудь вроде "what is compiler?" Это очень простой вопрос, не требующий зарываться в дебри.
Каким образом ваши доводы про KaleidoscopeJIT его опровергают?
Тем что компилятор далеко не "обычно" генерирует машинный код. Он не редко генерирует IR, CLI и еще множество высокоуровневых ассемблеров виртуальных машин. А кодогенерация последних может происходить как автоматически при вызове компилятора, скрывая от непросвещенного пользователя оптимизацию и кодогенерацию, так и во время выполнения.
наберите в Гугле
Ну раз Вы мне предоставили выбор: "a compiler is a computer program that translates computer code written in one programming language (the source language) into another language (the target language)"
Тоже верное определение. Так вот фронтенд компилятора не является computer program, это всего лишь программный модуль или компонент.
Что касается IR, то он не является ассемблером виртуальной машины. Нет виртуальной машины, способной непосредственно исполнить его команды (и не может быть, потому что он предполагает бесконечное количество регистров).
Так вот фронтенд компилятора не является computer program
Вы издеваетесь? А что это по Вашему? Не компьютерная программа или вообще не программа? Откуда Вы вообще такое определение выкопали?
ISO/IEC/IEEE 24765
computer program. a combination of computer instructions and data definitions that enable computer hardware to perform computational or control functions
Компонент, который не реализует конкретных функций компьютера, не является компьютерной программой.
Надо объяснять архитектору ИС, почему создание исполняемых программ является функцией компьютера, а создание промежуточного представления кода при компиляции – не является?
Вы хотите сказать, что фронтенд не содержит компьютерных инструкций и определений данных?
Вы уж простите, но даже это компьютерная программа:
#!/bin/bash
echo 'Hello, World!'
Так как она содержит как инструкцию echo, так и определение данных 'Hello, World!'
ISO/IEC/IEEE 24765
А вот это уже очень некрасиво! И совершенно непрофессионально.
3.522 computer program
a combination of computer instructions and data definitions that enable computer hardware to perform computational or control functions
a syntactic unit that conforms to the rules of a particular programming language and that is composed of declarations and statements or instructions needed for a certain function, task, or problem solution.
Вы будете уверять, что случайно скопировали определение не полностью?
Ну мы же говорим о программе как предмете, а не как синтаксической конструкции языка программирования. Вроде ясно из контекста.
Нет разницы, на каком языке.
Наконец-то. То есть фронтенд у LLVM Вы всё же признали компьютерной программой, а значит компилятором?
Осталось лишь решить, что "обычней". Три языка из десяти или девять из десяти )
Вот объясните мне, как из того, что "можно написать компилятор на bash", должно следовать, что "фронтенд llvm - это компьютерная программа, а значит компилятор"? Вот просто КАК???
Ну Вы же признали, что компилятор, вне зависимости от того, на каком языке он написан - компьютерная программа? Или это относилось только к компилятору на bash, но не относится к компилятору на C (clang, фронтенд LLVM)?
clang как фронтенд - это не компилятор (компьютерная программа), а часть компилятора (компьютерной программы). Независимо от того, на каком языке он написан.
clang как исполняемый модуль, включающий фронтенд, оптимизатор и бекенд - компилятор (компьютерная программа).
clang как фронтенд - это не компилятор
Разве он, в полном соответствии с определением компилятора не транслирует код из одного языка в другой? Например из C в IR. Или Вы придумали новое определение для компилятора?
часть компилятора (компьютерной программы)
Часть программы - тоже программа. В полном соответствии с Вами же приведенным определением.
Там прямо вверху написано, о чём идёт речь. Об инфраструктуре для написания компиляторов. Которая внутри себя имеет в том числе и определённый собственный сленг. Но в обычном понимании, о котором шла речь, компилятором называют всю программу, а не только её фронтенд.
Там прямо вверху написано, о чём идёт речь
При это оптимизатор с кодогенератором и компиляторы явно разделены. Причем Clang - лишь одни из множества компиляторов в IR.
в обычном понимании
То есть, по Вашему Roslyn не компилятор?
Компилятор, но специфический, не обычный.
Хотя кто-то его мог бы назвать и частью интерпретатора.
Тут не в терминологии вообще дело.
Компилятор, но специфический, не обычный.
Ого. Теперь всю инфраструктуру .NET тоже записали в "не обычные"? Я с этим категорически не согласен, так как C# уже много лет из десятки самых популярных языков программирования не выходит.
К слову, Oracle Java Complier тоже компилирует в байт-код JVM, а вовсе не в машинный код. Java тоже по Вашему "не обычный"?
Java тоже не обычный. Два языка из десятки популярных не являются обычными ни в каком разумном общем контексте. А вы спорите ради спора.
Java тоже не обычный.
А может это Ваше определение обычности не верно?
Два языка из десятки популярных не являются обычными ни в каком разумном общем контексте.
А сколько в десятке компилируемых в машинный код языков? Три.
А сколько поддерживают JIT компиляцию? Я уверен в девяти. Про Go просто не в курсе.
А вы спорите ради спора.
Я спорю ради доказательства ложности Вашего утверждения:
компилятор обычно генерирует машинный код
Это далеко не так. Некоторые компиляторы могут генерировать машинный код. Но в общем случае, компилятор лишь транслирует код из одного языка в другой. Совсем не обязательно машинный.
Про общий случай я не спорю. Но это вообще никак не относится к моему утверждению, с которым Вы взялись спорить.
Что касается JIT компиляции, то это функция интерпретатора, а не компилятора. Такой вот парадокс.
Что касается JIT компиляции, то это функция интерпретатора, а не компилятора.
С каких под JIT-компиляторы превратились в интерпретаторы? Докажите.
Это JVM, V8, CLI или LLVM-JIT с некоторой натяжкой можно назвать интерпретаторами. Но уж никак не компиляторы в эти коды.
Так скоро и систему команд AMD64 назовете не машинной, так как огромное количество команд там реализуются микрокодом.
Простите, вы уверены, что вы правильно понимаете, что такое JIT-компиляция?
Уверен. А вот Вы похоже не в курсе, как и в какой код компилируется Java, С#, CPython (в режиме компилятора) и т.п.
Тогда какая связь между компилятором в Java код и jit-компиляцией?
Компилятор Java компилирует в байт-код, который JVM (упрощенно) компилирует уже в машинный код. Не упрощенно, JVM компилирует не весь код, а часть кода может интерпретировать. Почему я и указал, что его с некоторой натяжкой можно назвать интерпретатором. Но уж никак не компилятор Java, компилирующий в этот байт-код.
Так компилятор Java не имеет к jit-компиляции никакого отношения.
Не понимаю о чём Вы. Он компилирует в байт-код для JIT-компилятора JVM. Я же подробно это описал. Не было бы компилятора в этот байт-код, JIT-компилятор JVM не имел бы вообще никакого смысла. Это можно назвать "никакого отношения"?
Он компилирует просто в байт-код для JVM. Есть jit-компилятор в JVM или нет, его вообще никак не заботит (в первом приближении).
Компиляция в байт-код не имеет никакого смысла, если этот байт-код не будет затем кем-то скомпилирован в машинный код. Но давайте прекратим демагогию со сменой темы.
И вернемся к нашим баранам:
Что "обычней"? Три языка из десяти наиболее распространенных или девять из десяти.
Байт-код может не компилироваться в машинный код, а непосредственно исполняться интерпретатором. Он для этого изначально и предназначен.
Если не заниматься подменой темы и написать прямо, то всё, что вы пишете - это игра словами и казуистика, возникшая из вашей неудачной придирки к ясному и простому утверждению, что компиляторы обычно не используют ассемблер в качестве промежуточного этапа создания машинного кода, хотя у учащихся зачастую складывается такое представление. И вот вы десятками сообщений наводите тень на плетень, вместо того, чтобы просто признать, что написали не по делу.
вашей неудачной придирки к ясному и простому утверждению, что компиляторы обычно не используют ассемблер
От подмены темы переходите ко лжи? Я писал противоположное: "Я вполне могу согласиться с утверждением, что компиляторы обычно не генерируют ассемблерную программу. Но я не согласен с утверждением, что компиляторы обычно генерируют машинный код."
И уже в четвертый раз. Где ответ на прямо поставленный вопрос?
На все прямо поставленные вопросы, которые я усмотрел в ваших комментариях, я дал ответы. Если вы хотите получить ещё какой-то ответ, сформулируйте вопрос в явном виде.
Вопрос был задан уже дважды. Тут и тут. И еще дважды я его не повторял, но просил на него ответить. Тут и тут.
Я уже доказал, что девять языков из десяти в ТОП-10 имеют компиляторы в промежуточный код. И только три из десяти - в машинный код.
Осталось лишь выяснить последнее: "Что "обычней"? Три языка из десяти наиболее распространенных или девять из десяти."
Я воспринимаю написанное не как вопрос, а как манипуляцию фактами в виде риторического вопроса. Тем не менее, если для вас это важно, я отвечу.
В изначальной постановке вопроса шла речь о компиляторах, а не языках, и не надо подменять одно другим.
Очевидно, что языки (пусть сами по себе и популярные, такие как Python), не предполагающие использование компилятора в качестве штатного инструмента, не могут использоваться в аргументации о распространённости компиляторов.
Jit-компиляция выполняется не компилятором, а интерпретатором, в качестве одного из необязательных, вспомогательных шагов процесса интерпретации. Наличие шага jit-компиляции не делает интерпретатор компилятором и не позволяет ему занять место в рассмотрении компиляторов.
Подавляющее большинство окружающих нас обработанных компиляторами (т.е. скомпилированных) программ представлено в виде машинного кода, и это очевидно любому наблюдателю. Поэтому никакая казуистика вам тут не поможет в аргументации.
Байткод тоже можно рассматривать как машинный код виртуальной машины. Но это не особенно важно в контексте предыдущего сказанного.
Теперь я ответил на ваш вопрос?
Я воспринимаю написанное не как вопрос, а как манипуляцию фактами в виде риторического вопроса.
Нет. Мы обсуждаем Ваше утверждение
компилятор обычно генерирует машинный код
Компилятор по определению транслирует из одного языка программирования (исходного) в другой (целевой). В частном случае, целевой язык может быть машинным кодом. Осталось лишь доказать, что это далеко не "обычно" для компиляторов.
В изначальной постановке вопроса шла речь о компиляторах, а не языках, и не надо подменять одно другим.
Я не подменяю, а лишь рассматриваю компиляторы десятка наиболее распространенных языков программирования.
Очевидно, что языки (пусть сами по себе и популярные, такие как Python), не предполагающие использование компилятора в качестве штатного инструмента, не могут использоваться в аргументации о распространённости компиляторов.
Во-первых, первое же слово в этой фразе - ключевой признак демагогии. Во-вторых, Python не просто предполагает, а принимает в качестве эталонного компилятор CPython, который компилирует исходный код на Python в байткод и сохраняет его в .pyc файлах.
Jit-компиляция выполняется не компилятором
Это не имеет значение и уход от темы. Обсуждается то, что именно компилятор транслирует исходный код в байт-код.
Подавляющее большинство окружающих нас обработанных компиляторами (т.е. скомпилированных) программ представлено в виде машинного кода, и это очевидно любому наблюдателю.
Во-первых, данная фраза уже ничтожна, так как опять содержит ключевой признак демагогии. Во-вторых, я чуть ли не на ежедневной основе деплою программы именно в байт-коде, а не машинном коде. На C#, Java, Python, T-SQL и т.п. В-третьих, даже на этой странице есть скомпилированный из какого-то языка wasm. В-четвертых, подавляющее большинство программ для Android представлено так же в байткоде.
Почему так? Попробуйте скомпилировать программу в машинный код с использованием AVX-512 и Вы с удивлением обнаружите, что на большинстве CPU, находящихся сейчас в эксплуатации, она работать не будет. А если скомпилировать ту же программу в CLI или JVM, то на тех CPU, где AVX-512 поддерживается, он будет использован.
Байткод тоже можно рассматривать как машинный код виртуальной машины.
Нельзя.
ISO/IEC/IEEE 24765
3.1652
machine code
computer instructions and data definitions expressed in a form that can be recognized by the processing unit of a computer
И опять нет ответа на вопрос. В пятый раз.
А вы считаете, что processing unit не может быть виртуальной машиной?
Тогда зайдите в свой андроид и посмотрите, сколько в его памяти занимает операционная система, написанная в машинных кодах, а сколько - приложения в байт-коде (не забыв вычесть размер ресурсов с данными).
Интересно также было бы узнать, куда и как вы деплоите pyc файлы.
Это не имеет значение и уход от темы. Обсуждается то, что именно компилятор транслирует исходный код в байт-код.
Верно. Одна беда, про jit зачем-то вспомнили именно Вы.
В общем, не зарывайтесь.
А вы считаете, что processing unit не может быть виртуальной машиной?
Может. Но не the processing unit of a computer.
Тогда зайдите в свой андроид и посмотрите, сколько в его памяти занимает операционная система, написанная в машинных кодах
В машинных кодах в операционной системе там только kernel, ART и несколько библиотек. Если смотреть по эмулятору в SDK, то чуть более 100 МБ. Всего в SDK файлов в машинном коде ~250 МБ. Только JAR файлов - более 2 ГБ. А JAR файлов приложений только на моем телефоне - больше десяти гигабайт.
Интересно также было бы узнать, куда и как вы деплоите pyc файлы.
В директорию "__pycache__" приложения. Вы знаете иные варианты? Вот мне даже интересно стало, У Вас что-ли при каждом старте контейнера в k8s весь код Python каждый раз заново компилируется в байт-код? И сколько времени k8s поднимает pod, если там этого кода много?
Одна беда, про jit зачем-то вспомнили именно Вы.
Потому что для компиляции или интерпретации байт-кода требуется именно он. Но Вы опять радостно уцепились за это, упорно уходя от темы.
В пятый раз. Где ответ на вопрос?
Но не the processing unit of a computer.
Компьютер может быть виртуальным (что и называется virtual machine). Или думаете, что машинный код какого-нибудь Intel Xeon перестаёт быть машинным кодом, если исполняется на эмуляторе?
В машинных кодах в операционной системе там только kernel, ART и несколько библиотек. Если смотреть по эмулятору в SDK, то чуть более 100 МБ. Всего в SDK файлов в машинном коде ~250 МБ. Только JAR файлов - более 2 ГБ. А JAR файлов приложений только на моем телефоне - больше десяти гигабайт.
А теперь вычтите из этих 10 гигабайт ресурсы с данными и оставьте только код (.class)
Интересно также было бы узнать, куда и как вы деплоите pyc файлы.
В директорию "__pycache__" приложения. Вы знаете иные варианты?
Так вы не pyc файлы в таком случае деплоите, а исходные файлы py с кешем интерпретатора в виде pyc. Результатом же работы компилятора является объектный или исполняемый код, образующий самостоятельное представление программы, используемое независимо от исходного текста. Компилятор (транслятор) – это буквально переводчик.
Одна беда, про jit зачем-то вспомнили именно Вы.
Потому что для компиляции или интерпретации байт-кода требуется именно он.
Не требуется.
В пятый раз. Где ответ на вопрос?
Я дал вам очень подробный ответ на то, что вы называете вопросом. Если этот ответ вас не устраивает, то ничем не могу помочь.
Компьютер может быть виртуальным
А можно без догм и демагогии? Я придерживаюсь такой, такой и такой терминологии. Принципиальная разница между байткодом (p-code или portable code) и машинным кодом в том, что первый независим от архитектуры и переносим, чего не скажешь о втором.
Результатом же работы компилятора является объектный или исполняемый код
Вы можете доказать, что результатом компиляции Roslyn или javac будет объектный или исполняемый код?
Я дал вам очень подробный ответ на то, что вы называете вопросом.
Вот вопрос:
Что "обычней"? Три языка из десяти наиболее распространенных или девять из десяти.
Если Вы не приведете скрин с Вашим ответом на этот вопрос, то уже второй раз окажетесь уличенным во лжи.
А теперь вычтите из этих 10 гигабайт ресурсы с данными и оставьте только код (.class)
Получится еще больше, так как считать буду уже не размер файлов в архиве JAR, а в распакованном виде. Проверил выборочно на нескольких наиболее толстых JAR. В среднем, размер только class файлов в два раза больше получается, чем размер всего JAR.
Вот мой ответ на ваш вопрос. Ваш вопрос содержит в себе ложную альтернативу, и поэтому потребовал более широкого ответа.
А можно без догм и демагогии? Я придерживаюсь такой, такой и такой терминологии. Принципиальная разница между байткодом (p-code или portable code) и машинным кодом в том, что первый независим от архитектуры и переносим, чего не скажешь о втором.
Вы, конечно, молодец, что нашли в интернете какие-то сайты в подтверждение своей точки зрения, но я, пожалуй, ради такого дела сошлюсь на Дональда Кнута. У себя в первом томе он называет код своей виртуальной машины MIX машинным кодом (например, на с. 178 третьего русского издания). А если такую терминологию использует Кнут, то и любому другому программисту совершенно точно не западло.
Ну и так, для справки, "P" в "P-code" изначально означает "Pascal" и "pseudo". Хотя термин быстро стал универсальным.
Вы можете доказать, что результатом компиляции Roslyn или javac будет объектный или исполняемый код?
Результатом компиляции javac является исполняемый код JVM в виде файла class. Как именно в деталях работает Roslyn, я не знаю, за отсутствием опыта работы с Windows. Думаю, что так же.
Вот мой ответ на ваш вопрос.
Не вижу скрина с ответом на прямо поставленный вопрос. Итого, два раза уличил Вам во лжи и уже сбился со счету, сколько раз в демагогии. Может хватит?
А если такую терминологию использует Кнут, то и любому другому программисту совершенно точно не западло.
Он называет машинным код не виртуальной, а мифической машины. А разницу между байткодом и машинным кодом он вообще не рассматривает. Вы мне предоставьте доказательство того, что байткод и машинный код - одно и то же, как Вы утверждали выше.
Результатом компиляции javac является исполняемый код JVM в виде файла class.
С таким же успехом можно назвать исполняемым исходный код на C/C++, так как он может быть исполнен одним из множества интерпретаторов.
исходные файлы py
А уж исходные файлы Python уж точно можно смело называть тогда исполняемым кодом )))
Как именно в деталях работает Roslyn, я не знаю, за отсутствием опыта работы с Windows.
Связь между .NET и Windows не больше, чем у Java и Solaris. У моего текущего клиента свыше 90% .NET кода выполняется в k8s под Debian.
Но опять вернемся к наши баранам.
Являются ли Rolsyn и javac компиляторами?
Согласны ли Вы, что рассмотрение компиляторов только для десятки наиболее популярных языков программирования будет репрезентативной выборкой?
Согласны ли Вы, что среди компиляторов десятка наиболее популярный языков только для трех языков поддерживается компиляция непосредственно в машинный код, а для девяти в байткод?
И снова, можно ли называть "обычным" то, что поддерживается для меньшего количества языков и меньшим количеством более-менее распространенных компиляторов?
Не вижу скрина с ответом на прямо поставленный вопрос. Итого, два раза уличил Вам во лжи и уже сбился со счету, сколько раз в демагогии. Может хватит?
А может вам хватит упиваться коньяком по утрам? Ответьте на этот прямо поставленный вопрос. Он настолько же некорректен, как и ваш, поскольку содержит ложную альтернативу.
Он называет машинным код не виртуальной, а мифической машины.
В чём вы видите разницу между виртуальной и мифической машиной?
Результатом компиляции javac является исполняемый код JVM в виде файла class.
С таким же успехом можно назвать исполняемым исходный код на C/C++, так как он может быть исполнен одним из множества интерпретаторов.
исходные файлы py
А уж исходные файлы Python уж точно можно смело называть тогда исполняемым кодом )))
Безусловно, исходные файлы Python являются исполняемым кодом, если у них установлен битик +x. Просто по определению исполняемого файла. Именно так это и работает. (А, кстати, файлы pyc - не являются).
То же самое будет относиться и к исходному коду на Си при наличии в системе интерпретатора, но это редкий, казуистический вариант.
Но опять вернемся к наши баранам.
Являются ли Rolsyn и javac компиляторами?
Являются.
Согласны ли Вы, что рассмотрение компиляторов только для десятки наиболее популярных языков программирования будет репрезентативной выборкой?
Не согласен.
Репрезентативной выборкой будет рассмотрение наиболее применяемых компиляторов.
Согласны ли Вы, что среди компиляторов десятка наиболее популярный языков только для трех языков поддерживается компиляция непосредственно в машинный код, а для девяти в байткод?
Не проверял, но допускаю это.
И снова, можно ли называть "обычным" то, что поддерживается для меньшего количества языков и меньшим количеством более-менее распространенных компиляторов?
"Обычным" можно называть то, что происходит чаще всего.
Не надо выискивать для выяснения обычной практики казуистические случаи вроде интерпретаторов языка Си или компиляторов Питона.
компилятор обычно генерирует машинный код, а не ассемблерную программу
Скорее всего тут недостаточно контекста, и всё зависит от того, что понимается под терминами "компилятор" и "программа".
Самый обычный (поставляется вместе с ОС) GCC 13.3.0 на моей машине при выполнении "gcc hello.c" ведёт себя так (это можно проверить с помощью strace -f или gcc -v):
Запускает компилятор "cc1", который читает с диска hello.c и записывает временный файл на языке ассемблера в $TMPDIR со случайным именем с суффиксом ".s".
Запускает ассемблер "as", который читает временный файл из п. 1 и записывает новый временный объектный файл в $TMPDIR со случайным именем с суффиксом ".o".
Запускает обёртку "collect2", которая запускает компоновщик "ld".
ld собирает программу из crt*.o и файла, полученного в п. 2, порождая динамически (с использованием загрузчика ld-linux-aarch64.so.1) слинкованный (с libc.so.6) исполняемый файл с именем a.out.
Являются ли компилятором "gcc" и/или (только) "cc1"? Является ли ассемблерной программой файл .s из п.1?
Чем операционная семантика отличается от денотационной, и они обе - от синтаксиса.
Если не секрет, то как вы объясняете это, чтобы студент понял, не заставляя написать компилятор? И сколько времени на это уходит?
Спасибо за уточнение, действительно, в отношении gcc моё утверждение неверно. Мало с ним работаю и никогда бы не подумал, честно говоря.
Вы правы, что контекст обсуждения был несколько другой. Студент не понимал, почему у него в среде разработки для языка высокого уровня окно с ассемблерным текстом называется "disassembly", хотя, казалось бы, происходит процесс прямого, а не обратного ассемблирования.
Чем операционная семантика отличается от денотационной, и они обе - от синтаксиса.
Если не секрет, то как вы объясняете это, чтобы студент понял, не заставляя написать компилятор? И сколько времени на это уходит?
Это как раз очень понятные вещи, если их объяснять простым языком.
Синтаксис – это буквально те буквы (или байты), которыми написана программа, и их классификация в группы (символы) по формальным правилам грамматики, такие как имена, ключевые слова, разделители и т.д. Компьютер не знает ничего, кроме синтаксиса, его работу в принципе можно представить, как преобразование одних цепочек байтов в другие по сложным синтаксическим правилам грамматики.
Семантика – это смысл, который видит в программе человек. Также условно, для простоты объяснений человеку, иногда считают, что компьютер формально работает с семантикой, анализируя программу, хотя для компьютера это всегда просто синтаксис.
Денотационная семантика – это то, какую задачу мы решаем данной конструкцией языка, а операционная семантика – как именно мы это делаем. Одинаковая денотационная семантика может быть у программ с разной операционной семантикой, и в этом заключена возможность оптимизации.
Вот, собственно, и всё.
Моя практика показывает, что студенты прежде всего видят в тексте программы операционную семантику.
У некоторых возникают проблемы с синтаксисом, особенно когда язык сам по себе синтаксически сложный. Иногда небольшие проблемы, а иногда и значительные, когда человек, например, не понимает, что в данном контексте означает круглая скобка. В таких случаях я заставлял студентов просто просматривать тексты произвольных программ и делать просто их лексический разбор: "ключевое слово, идентификатор, разделитель, идентификатор, операция, ..." Это довольно быстро помогает.
Самая проблемная вещь, по моему опыту – это денотационная семантика. Для того, чтобы по тексту программного кода понимать денотат, нужна прежде всего практика, насмотренность, и это никак, иначе чем практикой, не выработаешь. Только запоминание основных паттернов кодирования, на которые я стараюсь всегда специально обращать внимание студентов. Но есть вторая сторона проблемы: формулирование денотационной семантики прежде написания кода. Этот этап пропускают очень многие, и сразу рвутся с шашкой кодировать, вместо того, чтобы для начала уяснить для себя, что же мы хотим получить. Поэтому я и на готовом коде прошу студентов описать отдельно его операционную и денотационную семантику (а в некоторых случаях и синтаксис, как рассказано выше), и при написании кода прошу сначала сформулировать отдельно денотационную и операционную семантику, а потом уж писать.
В формализмы для описания денотационной семантики и преобразования этих формализмов я со студентами, конечно, не углубляюсь.
на первых порах … никак не мог въехать в "возвращаемое значение"
Тем, кто начинал с Паскаля, понятно, что возвращаемое значение - это то, чем функция отличается от процедуры.
this.age = age;
Этот пример непонятен только потому, что сам пример совершенно плохой. Сохранили переменную в свойство, а что и зачем - не показали. Нужно было показать обращение к этому свойству из другого метода без аргументов. И показать обращение к свойству извне объекта, где он будет уже не this.
И самое прикольное. Редко кто обращает внимание, что под термином "алгоритм" подразумеваются две разные вещи.
Какие?
Обычно в школе говорят, что алгоритм - это последовательность действий для достижения определённого результата. То есть он по определению дискретен, представлен в виде шагов.
Но когда говорят о квантовых или аналоговых компьютерах (или, например, о работе системы управления), то подразумевают, что алгоритм - это просто способ достижения определённого результата. Такое определение более широко.
Тьюринг в конце жизни много времени посвятил исследованию алгоритмов в широком смысле.
"Непонятки" в изучении программирования начинаются с ложного убеждения, что что-то существенно зависит от автора книги или преподавателя. На ранней стадии поможет только: медная задница и способность запоминать. Поэтому книжка нужна потолще. Препод нужен почаще и попродолжительнее. По большому счёту научить программированию человек может только сам себя. Книга это данные. А препод это стимул
Происходит так потому, что это аналогично телепортации пещерного человека в современный мегаполис. Слишком много значимых деталей, и мозгу банально надо время на простройку нейронных связей. Такое себе Loading.........N% которое может длиться годами
Шаг от функтора к монаде трудновато дался.
«Непонятки» в изучении программирования