>С чего Вы взяли, что ФП само по себе что-то делает в разы медленнее
>для реальных задач скорее будет 5 и 6
Так ведь все зависит от конкретной ситуации. Если скорость устраивает, вообще не важно какая разница в скорости и насколько могло быть быстрее. Я просто указал на то, что утверждения типа: «корректность важнее быстроты», нужно всегда принимать с оговоркой: «если быстроты достаточно для обеспечения корректности». А вообще, лучше избегать выражений в форме: «X важнее чем Y». Гораздо правильней будет «стремись оптимизировать X, при Y, лежащем в допустимом диапазоне».
>Впрочем, Вы там в сторону математического доказательства корректности углубились. Хотя по факту это не имеет смысла, достаточно того, что ФП упрощает то самое юнит-тестирование.
С этим согласен. Углубляться в это особо и не хотел, просто так уж получилось. Мысль в эту сторону пошла. На практике, я никогда бы таким заниматься не стал. Думаю, и никто бы не стал.
>Нет, корректность не нарушена. Программа корректно делает то, что от нее требуется. Да, делает медленно — но это вопрос повышения быстродействия при сохранении корректности результата.
Но если время работы является одним из требований, и оно не выполняется, то программа не выполнила своих функций. Либо, если все таки выполнила, то требования по времени были изначально неправильными и излишними. В любом случае, если производительность устраивает, то никаких вопросов нет, я просто говорил о том, что производительность может и не устраивать. Да и обсуждаемая статья именно об этом.
Со всем остальным я в принципе могу согласиться, особенно про ненужность формального доказательства корректности для большинства задач. Я об этом вообще заговорил только в контексте того, что это было заявлено, как решающее преимущество. Использовать аргумент, что это вообще не нужно — не стал, т.к. если бы это было реально достижимо для всей программы, это был бы серьезный плюс. Но если говорить об отдельных алгоритмах, то и спорить не о чем, можно тогда только эти алгоритмы и реализовывать на ФП, а остальное как удобнее. Это уже мультипарадигменность.
Что по поводу чистых функций и их проверки, то я лично не считаю чистые функции неотъемлемым атрибутом именно ФП. Мне ничего не мешает написать обычный метод, или даже процедуру, если хотите, которая будет принимать значения в качестве параметров и возвращать результат, не взаимодействуя с какими-либо глобальными данными и не имея побочных эффектов. Внутри это будет чистый алгоритм. А для внешнего наблюдателя — чистая функция. Любой процедурный язык это позволяет. Плюсы ФП не в том, что они позволяют писать такие функции, а в том, что они позволяют это делать быстрее и проще. И это становится актуально, когда таких функций надо писать много. Чтобы точно избежать недопонимания, это я не к тому написал, что ФП не нужно, а к тому, что даже если язык вообще не позволяет писать в функциональном стиле — это не повод его менять, по крайней мере, если нет реально серьезной потребности в функциональщине.
>Корректность лучше быстроты. Простота лучше сложности. Ясность лучше хитроумия. Безопасность лучше ненадежности
Это все очевидные вещи, но на мой взгляд, загвоздка тут в самом понятии корректности.
Что такое корректная программа? Это программа, работающая без ошибок. А что такое ошибка в программе? Есть хорошее определение: «В программном обеспечении имеется ошибка, если оно не выполняет того, что пользователю разумно от него ожидать» (Г.Майерс. Надежность программного обеспечения. — М.: Мир, 1980. стр. 12). То есть, в конце концов все упирается в разумные ожидания пользователя. А что делать если требуемая скорость работы явно оговорена пользователем? Или неявно подразумевается, что пользователю разумно ожидать, что какое-то действие программы будет выполняться, скажем минут за 5, а с нашими алгоритмами, оно выполняется за 30? Корректность в данном случае нарушена, т.к. программа не делает того, что от нее требуется. Так что быстротой можно пренебрегать не всегда, и только до определенного предела. То же и с простотой/сложностью. Если простое решение — неправильное, или работает слишком медленно, что как мы выяснили, тоже является неправильным, то придется применять сложное решение. Насчет хитроумия, функциональный код, как раз, выглядит весьма хитроумно. Ну а безопасность, проистекает из корректности. Корректный код и так должен быть безопасным. А программа, не успевающая обрабатывать запросы — ненадежная.
>Благодаря чистоте функций и неизменяемости состояний, в ФП легче доказать корректность решения.
Это верно только для каких-нибудь математических задач. Дело в том, что для строгой проверки корректности, нужно чтобы требования к программе были сформулированы так же строго. Насколько реально, для прикладных задач, строго сформулировать разумные ожидания пользователя? Как это вообще сделать? Кто должен этим заниматься, и сколько времени это займет? Не будет ли написание обычных юнит тестов быстрее? Что проще, набрать команду толковых тестировщиков, или набрать команду толковых математиков? И кому придется больше платить? Кто докажет, что требования в итоге сформулированы корректно? И кто докажет корректность интерпретатора, выполняющего функциональную программу? Где гарантия, что он одинаково работает на любом железе и при любом окружении, под нагрузкой, с временными задержками и т.д? Все равно, без тестирования, в условиях, приближенных к реальным, не обойтись.
Да и к тому же, сколько лет уже используется императивное программирование? До сих пор корректность работы программ была достаточной, и вполне неплохо проверялась с помощью тестов. Так что, это как минимум, не является острой проблемой, которую только ФП может героически решить. Что же касается научной сферы, где строгая проверка действительно актуальна, а проблемы скорости алгоритмов, наверное не очень критичны, то тут никто и не спорит, что функциональное программирование хорошо для этого подходит. Да и количество математиков на квадратный сантиметр, там побольше будет.
>И, кстати, корректно ли сравнивать ФП и ООП, и называть последнее императивщиной?
>Мне кажется, ООП — более высокий уровень абстракции
Уровень абстракции у ООП высок на этапе описания предметной области в виде структуры классов. Это, можно сказать, декларативная часть ООП. Описание классов и отношений между ними — декларативно, А код методов императивен. И работа с экземплярами классов происходит в императивном режиме. То есть сочетается сразу два уровня абстракции. Чем лучше мы отразим предметную область в терминах классов, тем более высокоуровневым будет наш код. То есть мы можем варьировать уровень абстракции. Возможно именно поэтому ООП пользуется таким успехом. Но, конечно же, у этого варьирования есть свои пределы. Именно поэтому, код в ОО стиле кажется избыточным в очень маленьких проектах — слишком много лишней декларативщины. И поэтому же, код становится слишком запутанным на очень больших проектах — мы не можем избежать императивного кода, а на большом проекте, накапливается его критическая масса. То есть абстракции, предоставляемой ОО подходом становится недостаточно. В этом плане функциональные элементы хорошо дополняют ОО язык, позволяя уменьшить количество императивного кода в некоторых местах. А те же лямбды помогают не засорять декларативную часть всякими служебными, одноразовыми методами, не имеющими никакого смысла в терминах предметной области. Но эти функциональные элементы не имеют особого отношения к чистому функциональному программированию. Ведь предметная область по прежнему остается описана в терминах классов, а основная часть логики по прежнему описывается императивно.
Но опять же, надо учитывать, что большинство применяемых ОО-языков не являются строго ОО-языками. Они все мультипарадигменные. Так уж получилось, что ОО-парадигма хорошо совмещается с элементами других парадигм. Наверное это вторая причина успешности ООП. Если подумать, из всех ОО-языков, которыми я хоть как-то владею, более-менее консервативным, в плане поддерживаемых парадигм, был только Delphi. При чем именно старый Delphi, в котором даже Generic'ов не было. И что-то я не заметил, чтобы он всем очень нравился. Так что, сколько бы не говорили о засилье ООП, на самом деле, самой популярной парадигмой была и остается мультипарадигменность. Потому что ни одна парадигма в отдельности не является достаточно универсальной, чтобы на ней было удобно делать абсолютно всё.
Ну почему сразу заказ? По моему в статье все логично. Вообще, если не вдаваться в конкретику, то можно сформулировать довольно кратко. Функциональные языки это очень высокий уровень абстракции. Гораздо более высокий, чем любой императивный язык. От этого, прежде всего, будет всегда страдать производительность. При этом, виртуальную машину, которая выполняет функциональную программу, можно оптимизировать, но, как и всегда, только под определенные классы задач, проиграв при этом где-то еще. А вот оптимизировать конкретный алгоритм мы практически не в силах, потому что абстрагированы от железа практически полностью.
И эта проблема не является эксклюзивной для функциональных языков. Каждый раз, когда мы поднимаемся на более высокий уровень абстракции, мы теряем в производительности. Но если при этом растет скорость и простота разработки, и вообще появляется хоть какое-то преимущество, всегда найдется сфера применения, где это преимущество окажется важнее недостатков. Вопрос только в том, насколько эта сфера применения будет широка.
И вот исходя из этого и следует определять, где ФП применимо, а где нет. В последнее время просто была тенденция, форсить функциональные языки везде и всюду, как какую-то новую религию. А потом уже и в комментариях на Хабре, на прочих форумах, и вообще в разговорах с другими программистами, я стал замечать, что некоторые видят написание чего-либо в функциональном стиле, как самоцель. Будто если программа написана на функциональном языке, то это ее главное преимущество. Поэтому появление таких вот контр аргументирующих статей вполне закономерно. Такое и с другими новыми технологиями/языками случается. Сначала появляется шквал статей, где какая-то технология описывается, как серебряная пуля. Следом идут статьи, где происходит срыв покровов, и объявляется, что серебро оказалось простой нержавейкой.
Программисты в своей массе вообще довольно «религиозны». Я конечно же имею в виду не традиционные религии, а фанатичное следование каким-либо трендам. Для многих ООП — это настоящая религия. А для других, вот — ФП. Есть те, для кого нет бога кроме MVC. А кто-то делает идола из соглашений по написанию кода. Встречались мне и более экзотические верования, например священный джихад против множественных return'ов из функции. Может и в других профессиях такое наблюдается, но мне почему-то кажется, что программисты, чаще всего участвуют в священных войнах. Проблема еще в том, что у нас это легко может выйти за пределы какого-нибудь форума. У многих есть возможность проталкивать свои идеи на практике. И вот тут надо проявлять осторожность.
Сначала, прочитав название статьи, думал, что речь пойдет обо всяких покетах, firefox hello, и прочих дзенах. И даже уже почти согласился. Но, поскольку это не твиттер, решил все же прочитать саму статью. Оказывается вы на поддержку новых стандартов замахнулись. В таком случае, хочу сказать, что категорически с вами не согласен. То, о чем вы говорите — это не ненужные функции, это новые функции. Даже «новейшие», как вы сами их назвали. Само собой, использоваться в боевых условиях, особенно в крупных проектах, они начинают не сразу. Во-первых новый API, очень часто, бывает нестабильным, и не во всех браузерах одинаков, а может и вовсе не поддерживаться. Во-вторых, людям еще нужно оценить необходимость использования той или иной функции в их конкретном проекте, и то, как именно её применить. К тому же, у всех крупных проектов и так есть какой-то roadmap, и план развития расписан наперед. Чем крупней проект, тем сложней и дольше этот план пересматривать. Разумеется, пройдет время, прежде чем эти функции начнут активно использоваться, но внедрять их в стандарт просто необходимо. Желательно с запасом. И чем раньше, тем лучше, потому что путь от стандарта до стабильной, повсеместной реализации занимает годы. Чтобы чем-то начать пользоваться через пару лет, нужно это предусмотреть уже сейчас.
И не надо путать частоту использования функции и ее нужность. Сколько раз вы пользовались огнетушителем? Большинство людей ответит: «Ни разу». Так может ну его нафиг? Ведь, 83% огнетушителей никем не используются. Или все же оставим их, на всякий пожарный? А еще, на самом деле, только 1% из 10 000 людей используют контрастные темы в компьютере или смотрят новости с субтитрами. А сколько процентов русскоговорящего населения читают Хабр?
Кто-то может вообще не использовать новую функциональность, а у кого-то весь сервис на ней будет построен. Все потому, что по сравнению со старой, базовой функциональностью, которая была и остается практически необходимым минимумом для создания любого сайта, новая — имеет более узкую, специализированную область применения. Это касается не только самых новых функций, но и тех, что уже успели хорошо прижиться. Едва ли вам удастся реализовать сайт без ссылок. А вот без видео вполне можно обойтись на многих типах сайтов. В то же время ютуб, без возможности встроить в страницу видео, не существовал бы. Вы, конечно, можете сказать, что он прекрасно работал и до появления html5 и тега video. Ну да, работал. На флеше. Вы, кажется, что-то говорили про безопасность? Так вот, чем больше умеет браузер, тем меньше нужны сторонние дырявые плагины.
Конечно, сравнивать какой-нибудь Vibration API с тегом video — не совсем честно. Это просто разные весовые категории. Но с другой стороны, мы всё дальше движемся в сторону создания универсальных web приложений, а это требует существенного наращивания функционала в браузерных движках. Ведь без хорошего запаса по функционалу, в том числе по интеграции с операционной системой и железом, ни о какой универсальности не может идти и речи. Разработчики просто будут предпочитать нативные приложения, в которых можно, и вибрацией управлять, и к датчику освещенности обратиться. Даже если сегодня это не требуется, мне, как разработчику важно знать, что я в принципе смогу это сделать, если от меня потребуют. Да и пользователи, при прочих равных, будут предпочитать приложения, которые подстраиваются под освещенность, и могут вибрировать, при необходимости, например, когда в чате упоминают твоё имя. В конце концов, из таких вот мелочей и строится удобство.
>то будет если два макроопределения совпадут?
Не совсем понимаю причем тут именно typedef? А что будет если просто имена двух разных классов совпадут? Да ничего не будет. Если они в пределах одного пространства имен, код просто не будет компилироваться.
>И каков шанс, что они будут знать один из тысяч языков? А ведь если мы говорим про маленькие, «специализированные» языки, то их, скорее всего, будут тысячи…
Вот оно, теперь мне стало ясно, в чем мы друг друга не поняли. Я не предполагал такое количество языков, и что они будут создаваться вообще на каждый чих. Я предполагал, что в виде отдельных языков будут отражены основные парадигмы программирования, и что эти языки можно будет каким-то стандартным образом совмещать. Языки эти будут более-менее чистыми, без излишеств. А так же будут более специализированные языки. Под специализированными языками, я понимал, например, языки для написания бэкенда, для работы с базами данных (на стороне самой БД уже есть SQL, но хотелось бы иметь стандартизированный слой для работы с БД, на стороне клиента, то что сейчас каждый язык делает по своему), для работы с текстом (те же самые регулярки), и т.д. Причем суммарно, разнообразие не увеличится, а уменьшится. То, что существуют регулярки для обработки текста приводит к упрощению, а не к усложнению. Ну и что, что надо выучить еще один «язык»? Зато потом можно применять его везде, а не изучать кучу методов для такой обработки в каждом языке. То же и с SQL. Было бы фигово, если бы каждый язык предоставлял свой синтаксис для запросов к БД. Какие еще вещи выделятся в отдельные языки, я не знаю. Может работа с сетью, а может обработка файлов. В итоге жизнь сама рассудит. Это еще один важный момент, я не призывал к созданию кучи языков, как к самоцели. Я лишь предположил, что это вероятно станет следствием создания единого стандарта, для взаимодействия различных языков программирования друг с другом. И вот это именно то, что я предложил — создать такой стандарт. На мой взгляд, это очевидно приведет к декомпозиции в сфере языков программирования, а вот в какой именно форме это выразится, я не уверен. Возможно будет как я предположил — сильная декомпозиция, а может появится несколько более простых диалектов C# (и других языков), для разных целей. Даже по этой теме мы видим, что все споры в основном сводятся к тому, что один человек не понимает, зачем нужна та или иная особенность языка, а другой ему отвечает, что это применяется там, здесь и еще вот тут. Так может и стоит разделить все эти вещи по разным языкам, раз уж это разные сферы применения? Сейчас этого не делается, чтобы была возможность совместить разный функционал при необходимости. Вот такую возможность и предоставит стандарт взаимодействия языков. А может и этого не будет, а просто будут использовать это для того, чтобы решить проблему обратной совместимости и не тянуть огромное легаси старых версий языка. Да даже если только одна эта проблема будет решена, я буду на седьмом небе от счастья. Чтобы не было больше таких вещей, как модификатор «private protected» в C#, или фигурные скобки вместо присваивания в C++.
>А в большинстве случаев они будут знать кучу разных других языков
Им всего-то надо знать хотя бы один нужный язык, чтобы принести пользу со старта. В крайнем случае, джун сможет быстро выучить нужный язык, и придти устраиваться через неделю.
>Ну вот, собственно, «маленькие» языки имеют ту же самую проблему
Не совсем так. В случае с JS фреймворками, они основаны на JS, который сложнее, каждого из этих фреймворков, и его тоже нужно выучить.
>Вы про какой-нибудь REXX или что-нибудь подобное — много слышали? А с языком 1С общались?
А что не так с REXX? Я так и писал: «в условиях, когда языки легко между собой интегрировать». Когда он поддерживался операционной системой и другими языками, читай, его легко было интегрировать, он был популярен. Сейчас он особо не поддерживается, во всяком случае «из коробки», поэтому о нем забыли. Логика как раз соблюдается. Современной аналогией можно считать регулярные выражения. Несмотря на брэйнфаковый синтаксис, они очень популярны, потому что поддерживаются во многих языках, т.е. легко интегрируемы.
Ну а 1С, он не интегрируется с другими языками, на сколько мне известно. И очень простым его не назовешь.
>Именно потому что «стек технологий» облегчает жизнь джуниору, но усложняет жизнь работодателю, а кто платит — тот заказывает музыку.
А чем именно он осложняет жизнь работодателю? Я тогда вообще ничего не понимаю. Одни работодатели плачутся, что не могут найти себе rockstar c++, другим не нравится система, упрощающая вход для джуниоров. А что же им тогда нужно? Чтобы проект уровня Facebook, могла сопровождать уборщица с минимальным окладом?
>приглашают работать в команду со своим «мини-языком» (или, ещё хуже, со своими «мини-языками»)
Что значит со своим? Собственной разработки? Не думаю что будет все настолько диверсифицированно. Зачем людям делать свой язык, если можно решить задачу с помощью существующих? Ведь написать язык это еще сложнее, чем свой фреймворк сделать. Такое осилят только очень крупные компании, и в условиях, когда языки легко между собой интегрировать, их языки быстро перейдут из разряда «своих», в разряд общеупотребимых. А если кто-то и будет клепать проприетарные языки, похожие на уже существующие, то разве сложно выучить язык, если он простой, и похож на уже существующий, который ты знаешь?
>если язык «хорошо заточен» под определённую область (как какой-нибудь APL), то он оперирует концепциями, которые в других языках выглядят сильно по-другому
Это уже больше относится к изучению новых концепций и парадигм. Сложность тут не от языка зависит. И если такой заточенный язык нужен, его и сегодня создадут, только о совместимости и интеграции с другими могут не подумать. Если же концепция человеку знакома, т.е. он не новичок в предметной области, то изучение такого языка наоборот будет для него естественным. Читая стандарт такого языка, строчку за строчкой, он будет лишь кивать головой и приговаривать: «Ну конечно», «Само собой», «Так и надо», «Я бы тоже так сделал», и т.д.
>если язык реализует известную тебе парадигму», то он, скорее всего, не нужен вообще
Обычно, исторически так складывается, что несколько языков развиваются параллельно, а потом разница у них оказывается в деталях. И «одинаковые» языки продолжают существовать по двум причинам:
1) Кодовую базу терять жалко, начав писать проект на одном языке, нельзя продолжить на другом. Языки хоть и похожи, но не очень совместимы между собой. Если кратко, то легаси.
2) Кому-то могут быть важны вот эти самые детали, различия между языками.
Соответственно я и предполагал, что многие различия уйдут в сопрягаемые миниязыки. И для каждой мажорной парадигмы, со временем, останется небольшое количество языков, либо вообще один язык. И легаси уже не помешает этому процессу. Скорее все же их останется несколько. Некоторые детали не слишком удобно будет выносить отдельно. Но языки будут просты и похожи. Зная один, очень быстро освоишь другой. Образование тоже сможет адаптироваться к этому. Будут специальные учебные материалы, типа: «язык B, для тех, кто знает язык A». Сейчас, я например не смог найти книжку: «Java, для тех кто знает C#». Может дело в том, что отличий все же слишком много, и подобная книга оказалась бы толще, чем мне представляется.
>К сожалению «маленькие языки» делают эту проблему только острее.
То есть вы считаете, что система, которую я описал, когда два джуна, хорошо знающих каждый свой небольшой язык, успешно справляются, каждый со своими небольшими задачами, и параллельно друг друга учат и сильнее погружаются в процесс — не сработает? Можете объяснить почему?
Мне почему-то кажется что должно сработать. Вот даже с сегодняшними реалиями, в компанию, разрабатывающую сайты, приходит человек, знающий только SQL Ведь можно ему поручить писать хранимые процедуры. А параллельно, он будет учиться, не только использовать, но и разрабатывать базы данных. Совершенно независимо от этого, его учат, например, писать регулярные выражения. И вот он уже может писать их, помогая, как в бэкенде, так и во фронтенде. Параллельно он изучает html и css. Изучив, он уже и верстать может. Следом он начинает изучать JS. С последним конечно придется повозиться. Человек постепенно обрастает знаниями, становясь full stack разработчиком. Но вход у него получается плавный, и даже со старта, он был полезен и выполнял реальные «боевые» задачи, зная только SQL. С каким-нибудь навороченным языком, типа C#, проблема в том, что если человек уже освоил основные алгоритмические конструкции, типы данных и структуры, но все еще не въехал в наследование, дженереки, лямбды, делегаты, интерфейсы и LINQ, он почти бесполезен в работе. Даже если сам он уже дорос, чтобы писать простой код, он откроет чьи-то исходники и ужаснется. У меня так было, когда в институте учился. Вроде сидишь, учишь, учишь, по предмету пятерки, курсовые сдаешь, а открываешь «реальный» код, и ничего понять не можешь. У меня вообще такое чувство, что я тот же C# раза четыре выучил, на самом деле. Вообще, любой язык сейчас, приходится учить, минимум дважды. Сначала, ты изучаешь, как на нем писать, в принципе, а потом изучаешь, как писать принято/правильно. Если язык более универсальный, то потом ты еще узнаешь что этих самых «принято/правильно» много разных, в зависимости от области применения. Вот вам и третья итерация изучения. А потом еще идет четвертая — изучение мощного, навороченного фреймворка, под конкретную задачу.
В этом плане, JS переплюнул всех, на мой взгляд. Выучил JS, а как же JQuery? А теперь изучи десять разных способов объявления объекта, и пять способов реализации наследования. Вот теперь ты готов начать изучать язык по настоящему. Angular, React… Постой, постой, зачем ты изучаешь первый ангуляр? Уже пора второй. Хотя знаешь, первый тоже пригодится. В итоге приходишь на работу устраиваться, и тебе говорят: «Ну знаете, пока вы все это учили, вышло пять новых фреймворков, каждый из которых, как отдельный язык, поскольку каждый предполагает свою философию, и написание кода в своем собственном стиле. А еще появилось три новых стандарта языка, и половина тех функций, старых фреймворков, что вы учили, больше не нужны.»
Проблема, на мой взгляд в том, что на работе, в каждый момент времени, требуется знание конкретного фреймворка, но чтобы до него добраться, надо сначала хорошо изучить основной язык, со всем его многообразием и многоликостью, а потом уже только фреймворк. Да еще и разные фреймворки, выполняющие схожие функции, имеют в качестве основы разные языки. Если бы роль фреймворка выполнял простой, специализированный язык, то нужно было бы выучить только его, и он был бы даже проще обычного языка, поскольку не такой универсальный. Особенно это бы чувствовалось, при изучении нескольких фреймворков. Например для изучения asp.net, django и rails, не требовалось бы учить C#, Python и Ruby. А может и вовсе не было бы такого многообразия фреймворков, ведь основное их отличие в том, какой язык положен в основу.
Ну а особенности предметной области учить придется в любом случае, будь то язык или фреймворк. Это мы никак не упростим.
>А ему это и не нужно. Он ищет специалиста со знанием C# — а про конкретный стиль нанятый работник узнаёт на месте.
А будет искать специалиста, со знанием и умением применять определенные парадигмы и стили, а конкретный язык разработчик узнает на месте. Язык освоить проще, чем новую парадигму. Особенно, если язык простой.
>Изучение любого языка, даже очень простого — это куда более серьёзная головная боль, чем изучение пары новых фич, добавленных в существующий язык.
Это вы рассуждаете с точки зрения того, кто уже знает язык. В идеале начал его изучение, когда язык только появился. Такой человек растет вместе с языком. Новичок же вообще не знает за что схватиться. Это как раз приводит к дефициту кадров, и к тому, что за ветеранами языка начинается охота, как за единорогом, т.к. порог входа со временем повышается, новичков прибывает все меньше, и знания языка у них неполные, а более опытный разработчик, не только язык знает в совершенстве, но и опыта имеет много. И поскольку это происходит со всеми языками, то специалисту в одном языке трудно перейти на другой, даже чисто психологически, потому что тут ты гуру, а там будешь джуном, с соответствующим статусом и зарплатой. Именно поэтому я и говорю об упрощении отдельных языков, с превращением набора знаний в некий конструктор, который можно постепенно дополнять. И если языки по прежнему будет очень сложно изучать, значит их не достаточно упростили. А вообще, чем больше языков ты знаешь, тем проще изучать новые. Особенно, если язык реализует известную тебе парадигму. К тому же, новичкам тоже будет намного проще. Работодатель сможет взять джуна, который знает пару простых языков, используемых компанией. И этому джуну сразу можно будет давать реальные задачи. Он сразу будет понимать чужой код, написанный до него, и сам может писать так же. А остальной стек языков, будет изучать постепенно, параллельно с работой и под руководством других программистов. Причем, внимание, не обязательно сеньоров. Такой же джун, со знанием другого языка сможет его научить. Они научат друг друга. В этом и суть упрощения, ведь сложность сейчас состоит не столько в том, что надо выучить много всего, а в том, что надо выучить много всего СРАЗУ, а до этого ты бесполезен в продакшене. Если же подмножества используемых технологий имеют четкое разграничение, не нужно знать их все на старте. Можно начать с небольшого стартового набора, и развиваться постепенно. Это как декомпозиция в коде, когда мы разбиваем один большой метод, на несколько маленьких, минимизируя интерфейс между ними.
>Думаете зря Google создал Go?
Говоря о простых языках, я как раз и представлял что-то вроде Go. Точнее некую комбинацию, вот таких простых языков общего назначения, как Go, и более узких небольших языков, которые добавят глубины. Я как-то, пару месяцев назад, взялся его изучать, сделал тестовый проект. В принципе, язык реально выучить за пару дней. И это при том, что там не только синтаксис свой, но и много концептуальных вещей, новых для меня. Конечно, сейчас я успешно забыл, большую часть, потому что нет возможности на практике использовать. Но это не страшно. Появится подходящий проект, просто за день повторю все, и начну писать. Главная проблема Go, на мой взгляд, низкая расширяемость. Нету средств для обобщенного программирования, нету шаблонов. Это позволяет сохранить язык простым, так что это и преимущество тоже. Но и ограничение. Если же будет возможность совмещать его модули с другими языками, такой проблемы не будет. Не хватает универсальности одного языка, дополни его другим. Языки просто перестанут пытаться стать серебряными пулями, а будут просто занимать свои ниши.
В том же Go, кстати есть и пример того, как сопрягать разные языки. Сишные модули транслируются в конструкции, нативные для Go. Что важно, это заложено в стандарт. Сопрягаемость с Си, это то, за счет чего взлетел C++ в свое время. Тогда, ради совместимости, было решено сделать языки похожими. Go показывает другой путь. Языкам не обязательно быть похожими, чтобы быть совместимыми. Нужно лишь стандартизировать способ использования одного языка из другого.
Вообще, может вы и правы, и настолько радикальных изменений, как я описал не будет, но во всяком случае, стандартизация сопряжения языков, даст нам решение проблем обратной совместимости, позволит более быстрое внедрение новых технологий разработки, с сохранением старой кодовой базы, и даст больше шансов новым средствам разработки «взлететь». Существуют же всякие стандарты для операционных систем, тот же POSIX, есть стандартные сетевые протоколы, модель OSI, а как доходит до языков программирования, то кто во что горазд.
По поводу предложения своих вариантов, есть у меня одна идея. Хотя она и кажется мне слишком фантастичной. Но последнее время все чаще о ней думаю.
Сначала о проблеме, как я ее понимаю, и откуда она на мой взгляд проистекает. Языки со временем усложняются. Это касается всех активно используемых языков. Особенно это заметно на примере языков с долгой историей. Почему так происходит? Причин, как мне кажется, четыре. Во всяком случае основных.
Во-первых, для разных классов задач подходят разные инструменты, а чтобы один инструмент подходил под многие задачи, он должен быть универсальным. Проблемы у всех универсальных инструментов примерно одинаковые: повышенная сложность и меньшая эффективность, по сравнению с узкоспециализированными инструментами. Эффективность зачастую не так критично падает, а вот сложность может расти очень сильно.
Во-вторых, люди стремятся использовать, прежде всего знакомые им инструменты. Особенно учитывая, что наиболее популярные языки довольно навороченные, учить их долго и сложно, а менее популярных — столько, что жизни не хватит, даже примерно их все оглядеть, и неясно что из них выбрать. Это толкает создателей инструментов, делать их все более универсальными. А единственный способ это сделать — наращивать функционал.
В-третьих, разные классы задач пересекаются между собой, так или иначе. Многие решаемые задачи являются составными частями большого проекта. Бывает, что одну подзадачу было бы удобней решить с помощью одного инструмента, а другую — с помощью другого. Но в программировании это означает, что мне удобно было бы часть проекта написать на Си, часть на С#, а что-то на Scala. Возникает проблема — как потом все это совместить? Гораздо удобней в таком случае, если один язык позволяет написать код в разных стилях и с использованием разных парадигм.
В-четвертых, мир быстро развивается, особенно сфера IT, поэтому языкам программирования тоже приходится стремительно развиваться, чтобы не опоздать за прогрессом. А требования обратной совместимости, не позволяют удалить или переделать старое. Можно только добавлять новое. Поэтому в старых языках проблема со сложностью стоит особенно остро. Да и новый функционал выглядит не всегда логично из-за этого. Взять тот же модификатор «private protected» в C#7. Сама идея хорошая, а синтаксис дурацкий. Если же прекращать развивать старый язык и просто делать новый, то возникнет проблема, как совместить старый код, написанный для старого языка с новым кодом. Ну не выкидывать же проверенные и хорошо отлаженные библиотеки. В свое время C++ перетащил в себя кучу архитектурных решений из C, только чтобы быть с ним максимально совместимым. И ведь взлетел, во многом, благодаря этому.
Ну а теперь к предлагаемому мной решению. Функционал естественно должен развиваться. Крупным проектам бывает необходимо совмещать разные подходы для реализации их составных частей, и интеграция должна быть максимально простой. Идти в ногу со временем тоже нужно. Так как же всего этого добиться, не усложняя языки программирования? Ответ на поверхности — нужно создавать много простых языков для разных задач. А чтобы не терять простоту совмещения разных подходов между собой, и возможность использования кода, написанного для других языков, надо сконцентрироваться на том, чтобы эти языки между собой легко стыковались. То есть, чтобы модуль, написанный на одном языке, было так же просто использовать из другого, как если бы они оба были написаны на одном языке.
Сейчас какой основной способ использования кода одного языка из другого? Скомпилировать библиотеку и ее слинковать. Лично мне кажется, что это никуда не годится. Во-первых в разных ОС формат библиотек и методы их линковки разные, во-вторых подключение таких библиотек сложно назвать простым и удобным. Прежде всего проблема в том, что языки не проектируются с расчетом на легкое использование кода друг друга. Вот это и надо исправлять. Нужен простой и современный стандарт, которому должны будут соответствовать языки, чтобы быть взаимно совместимыми. Тот же .Net и так является семейством языков. Надо только развить эту идею до должного уровня. И тогда не придется в один язык пихать абсолютно всё. И об обратной совместимости можно было бы не париться. Представьте, в том же С++, не пришлось бы придумывать использование фигурных скобочек для присваивания, чтобы избежать неявного приведения типов. Просто в модуле указываешь версию языка, и типы перестают неявно приводится при обычном присваивании с помощью знака равно. Что-то на подобие «use strict» в современных версиях JS. Можно было бы даже использовать разные версии компиляторов для старых и новых модулей, чтобы код самого компилятора не усложнялся.
В общем, мне кажется, что будущее за расширяемым семейством простых специализированных языков. По функционалу это будет как один большой суперъязык, но его подмножества будут четко разграничены, и не надо будет учить его весь, а только необходимые тебе части. Сейчас ты не можешь сказать, что знаешь С#, если не знаешь всех его составляющих. К примеру, нужно обязательно знать оба синтаксиса LINQ. Дело не столько в синтаксисе даже, а в том, что все эти синтаксические штуки, про которые написано в статье, предназначены для разных задач, и программирования в различных стилях. Мало кто решает все типы задач, и использует все возможные стили. И работодатель тоже, как правило, не может сформулировать, владелец какого из стилей им нужен. Вот и получается, что многие вещи ты не используешь, но знать их нужно. А держать в голове, то чем не пользуешься, вообще тяжело. Выучить — не проблема. Проблема — не забыть. При дроблении функционала на разные языки таких проблем не будет. Расширяемость, так же будет намного выше, чем у обычного языка. Не будет проблем обратной совместимости. Исчезнет главная проблема новых языков — малое количество готового кода и компонентов. Один и тот же класс задач смогут реализовывать разные взаимозаменяемые языки. Конкуренция языков будет высокой, ведь перейти с одного на другой, для разработчиков будет не сложно. Скорость эволюции языков будет соответствующая. По сути, два разных синтаксиса LINQ, в такой системе могли бы быть разными языками. Распространение получил бы наиболее удобный, а второй — просто исчез. Либо оба заняли бы свою нишу, не мешая друг другу.
В принципе, решаются все четыре описанные проблемы:
1) От слишком универсальных языков, и их сложности, мы уходим.
2) Языки становятся проще, учить их легче, и даже из непопулярного языка можно использовать компоненты, написанные на более популярных.
3) Пересекающиеся задачи пишем на подходящих языках, а потом все стыкуем.
4) С обратной совместимостью проблем нет — несовместимую со старой, новую версию языка, считаем новым языком, а использовать старый код из нового — не проблема, уж если разные языки совмещаем без проблем.
>И если кому-то алкоголь
>помогают
>без нанесения особого вреда окружающим
Вся проблема в том, что именно такая комбинация бывает в исчезающе малом количестве случаев. Вообще, я ни разу такого не встречал, просто умом я делаю небольшое допущение, что может быть это все таки возможно. Но «сердцем» я в это не верю. Уж слишком сильно алкоголики отравили мою жизнь. И нет, речь не только о крепких напитках. Самое обычное пиво пробуждает в некоторых людях неслабую агрессию. Может это и не повод запрещать алкоголь, но с алкоголиками нужно активно бороться, чего, на мой взгляд, не происходит в моей стране. Это кстати очень хорошо показывает, насколько лицемерна наша власть, и всякие подлые Мизулины. Сколько всего они сегодня запрещают, чтобы «защитить детей». Все это ложь. Я был ребенком, и невыносимо страдал от алкоголиков. И никто меня не защитил. И сегодня, миллионы таких же детей, никто не защищает. Ведь нарисованные порнокартинки, по мнению власти, куда опаснее для детей, чем бухой папаша. Конечно, можно сказать, что проблема в людях. Вот только таких людей ну очень много, и проблем от каждого из них тоже очень много. И если бы не алкоголь, от этих самых людей, проблем было бы гораздо меньше. Не может адская машина работать без топлива.
И если уж попытаться отстраниться от эмоций, можно попытаться сравнить статистику, сколько тяжких преступлений совершается на почве алкоголя, а сколько из-за сладкого, жирного, острого, телевизионных сериалов, ток-шоу, аниме, комиксов, компьютерных игр, любительского спорта. Думаю, даже если все остальное вы сложите вместе, алкоголь победит с ошеломляющим перевесом. Еще более показательно будет, если вычесть из статистики те случаи, когда суд признал преступника невменяемым. Псих может по любой причине вытворить что-то ужасное, так что случаи с ними не являются показательными.
З.Ы. Прошу прощения за негатив. Слишком уж болезненная тема для меня.
Я не рассматриваю применение низкоуровневых инструментов, как чисто академический поход. Я говорил про неуместность их использования для реализации бизнес логики. Говоря про чисто академическую точку зрения я имел в виду попытки обосновать использование таких инструментов, через математическое доказательство того, что этих инструментов теоретически достаточно. Подобные доказательства пишутся не для того, чтобы люди кидались писать СУБД или браузер на ассемблере. Хотя ассемблер ведь полный по Тьюрингу. На нем что угодно можно написать. Так же и с знаменитой троицей Дейкстры. То, что он рассматривал программу, как математический объект, как раз говорит о том, что его рассуждения имеют интерес, прежде всего, с математической (академической) точки зрения. Такие изыскания очень важны и они ложатся в основу разработки всех языков программирования, но пытаться использовать их" в лоб" для работы в продакшен, это уже фанатизм какой-то. И посмотрите на пост, с которого началась эта ветка. Там человек говорит и про указатели тоже, а не только про Дейкстру. То есть он предлагает использовать низкоуровневые средства и минимальный набор алгоритмических конструкций, потому что этого «достаточно, чтобы написать любой алгоритм». Отсюда и взялись у меня указатели и регистры, Дейкстра тут действительно ни при чем.
Академики конечно же не дураки, и будь перед ними инженерная задача, они бы ее решили не хуже инженеров. Ну может на чем-нибудь и набили шишек с непривычки. И в итоге предложили бы вполне себе инженерное, а вовсе не академическое решение. Просто обычно они решают совсем другие классы задач. Задачи академические, и решения академические. Например, доказать, что решения нет, в их случае тоже результат. От инженера, такого ответа никто никогда не примет. Если начальство сказало нарисовать прямую линию в форме котёнка, инженеру придется как-нибудь изловчиться. Ведь он же эксперт.
Что касается требования открыть конкретно одну банку, подобного рода проекты обычно всегда, либо вырастают в более крупные, либо становятся составной частью более крупных проектов. По крайней мере, мой опыт именно таков. Возможно так бывает не везде.
З.Ы. Про трату времени на комбайн ответил ниже по ветке. Если кратко, то я не предлагал создавать комбайн, а лишь использовать готовый.
Ну с миллионом-то я перегнул конечно, это было просто утрированное преувеличение. Я собственно в конце так и написал «хоть в какой-то степени масштабируемым», что подразумевает небольшой разумный задел на будущее.
Да и говоря про комбайн, я не имел в виду бросаться пилить свою собственную вундервафлю. Речь же шла не про создание тапок, ложек, консервных ножей или комбайнов, а про их использование. Так что, исходя из контекста, под комбайном я предполагал использование какого-то готового мощного фреймворка или библиотеки, с расчетом что мелкая задача будет расти, и фреймворк перестанет быть излишним. Собственные комбайны, наоборот, обычно возникают от того, что кто-то начал делать проект на коленке, не оценив его перспектив, затем вовремя не спохватился, чтобы все переписать, и по мере роста проекта, применяемые в процессе костыли разрослись настолько, что стали «фреймворком».
Устная речь в принципе менее строга, чем письменная. Она подвержена, как региональной дифференциации, так и временным флуктуациям. Поэтому письменная речь не должна оперативно подстраиваться под устную. Только если какая-то норма закрепилась достаточно прочно, и ее придерживается подавляющее большинство, можно закреплять эту норму в письменности.
>Потому что выделение публичного property, который просто отображен на внутреннюю переменную 1 к 1 ничем не отличается от нахождения этой переменной в публичной зоне видимости.
Позволю себе с этим не согласиться. Отличия есть, и они существенны.
1. Свойство нельзя передать по ссылке.
int Val = 0;
int PropVal {get;set}
void ChangeValue(ref int val){val=5;}
…
ChangeValue(ref Val); //работает
ChangeValue(ref PropVal); //ошибка компиляции
Что это означает для нас? Прежде всего то, что мы не можем в будущем заменить публичное поле, на публичное read/write свойство, не сломав обратную совместимость нашего кода. Ведь тот, кто наш код использовал, вполне мог передавать это поле по ссылке, и тогда его код перестанет компилироваться. Так что, если вдруг нам понадобилось добавить немного дополнительной логики к чтению/записи данного поля, например добавить событие на изменение значения, мы уже не сможем так просто этого сделать. Сделав же изначально, свойство вместо открытого поля, мы оставляем себе пространство для маневра.
2. Интерфейсы не могут содержать полей, только методы и свойства. Так что тут у нас и выбора особого нет. Если мы хотим в интерфейсе отразить возможность полного доступа к каким-то данным, нам придется использовать свойство. А поскольку надо сохранять единообразие кода (нам не нужно, чтобы код, являющийся частью интерфейса, сильно выделялся по сравнению с остальным), в объектах тоже имеет смысл использовать свойства. К тому же, все что имеет модификатор доступа, отличный от private — является частью интерфейса нашего класса. А значит, по хорошему, должно соответствовать требованиям, предъявляемым к интерфейсу: никаких полей, только методы и свойства.
А какое отношение указатель на ячейку памяти, и работа с регистрами процессора имеет к тому, чтобы забить в базу накладную от контрагента? Использование слишком низкоуровневых инструментов для написания какой-нибудь бизнес логики может быть не менее абсурдным, чем открывание консервов тапками. Даже если с чисто академической точки зрения это в принципе возможно. И базисы можно подбирать разные. Если кто-то докажет, что двух ложек и тапка действительно достаточно, чтобы открыть консервы, можно будет считать этот набор базисом. Не единственным, но одним из возможных. Например, все логические операции можно выразить через стрелку Пирса. И в каких-нибудь электро схемах это наверняка используется. Но в программировании мы почему-то используем базис «и, или, не», как более интуитивный. Хотя стрелки Пирса было бы необходимо и достаточно.
Вообще пример с тапком и ложками может и не самый удачный. Это просто мем, на самом деле, который частенько мне вспоминается, когда я слышу предложение, делать что-то с помощью неудобных инструментов. Более правильным примером была бы попытка построить многоэтажный дом, используя только кирпичи, цемент и мастерок.
Что же по поводу использования электрических комбайнов, то зачастую это бывает излишним, да. Но если мне надо открыть не одну консервную банку, а несколько тысяч, консервный нож мне уже не подойдет. Хотя им и можно открыть каждую из банок в отдельности, но чтобы открыть тысячу в разумные сроки, нужен комбайн. И даже если сегодня мне поставили задачу открыть именно одну банку, чутье инженера подсказывает, что как только я эту задачу закончу, далее от меня потребуют открывать миллион банок в минуту. Поэтому, пока найденное мной решение не будет хоть в какой-то степени масштабируемым, я не пойду докладывать, что задача выполнена.
>для реальных задач скорее будет 5 и 6
Так ведь все зависит от конкретной ситуации. Если скорость устраивает, вообще не важно какая разница в скорости и насколько могло быть быстрее. Я просто указал на то, что утверждения типа: «корректность важнее быстроты», нужно всегда принимать с оговоркой: «если быстроты достаточно для обеспечения корректности». А вообще, лучше избегать выражений в форме: «X важнее чем Y». Гораздо правильней будет «стремись оптимизировать X, при Y, лежащем в допустимом диапазоне».
>Впрочем, Вы там в сторону математического доказательства корректности углубились. Хотя по факту это не имеет смысла, достаточно того, что ФП упрощает то самое юнит-тестирование.
С этим согласен. Углубляться в это особо и не хотел, просто так уж получилось. Мысль в эту сторону пошла. На практике, я никогда бы таким заниматься не стал. Думаю, и никто бы не стал.
Но если время работы является одним из требований, и оно не выполняется, то программа не выполнила своих функций. Либо, если все таки выполнила, то требования по времени были изначально неправильными и излишними. В любом случае, если производительность устраивает, то никаких вопросов нет, я просто говорил о том, что производительность может и не устраивать. Да и обсуждаемая статья именно об этом.
Со всем остальным я в принципе могу согласиться, особенно про ненужность формального доказательства корректности для большинства задач. Я об этом вообще заговорил только в контексте того, что это было заявлено, как решающее преимущество. Использовать аргумент, что это вообще не нужно — не стал, т.к. если бы это было реально достижимо для всей программы, это был бы серьезный плюс. Но если говорить об отдельных алгоритмах, то и спорить не о чем, можно тогда только эти алгоритмы и реализовывать на ФП, а остальное как удобнее. Это уже мультипарадигменность.
Что по поводу чистых функций и их проверки, то я лично не считаю чистые функции неотъемлемым атрибутом именно ФП. Мне ничего не мешает написать обычный метод, или даже процедуру, если хотите, которая будет принимать значения в качестве параметров и возвращать результат, не взаимодействуя с какими-либо глобальными данными и не имея побочных эффектов. Внутри это будет чистый алгоритм. А для внешнего наблюдателя — чистая функция. Любой процедурный язык это позволяет. Плюсы ФП не в том, что они позволяют писать такие функции, а в том, что они позволяют это делать быстрее и проще. И это становится актуально, когда таких функций надо писать много. Чтобы точно избежать недопонимания, это я не к тому написал, что ФП не нужно, а к тому, что даже если язык вообще не позволяет писать в функциональном стиле — это не повод его менять, по крайней мере, если нет реально серьезной потребности в функциональщине.
Это все очевидные вещи, но на мой взгляд, загвоздка тут в самом понятии корректности.
Что такое корректная программа? Это программа, работающая без ошибок. А что такое ошибка в программе? Есть хорошее определение: «В программном обеспечении имеется ошибка, если оно не выполняет того, что пользователю разумно от него ожидать» (Г.Майерс. Надежность программного обеспечения. — М.: Мир, 1980. стр. 12). То есть, в конце концов все упирается в разумные ожидания пользователя. А что делать если требуемая скорость работы явно оговорена пользователем? Или неявно подразумевается, что пользователю разумно ожидать, что какое-то действие программы будет выполняться, скажем минут за 5, а с нашими алгоритмами, оно выполняется за 30? Корректность в данном случае нарушена, т.к. программа не делает того, что от нее требуется. Так что быстротой можно пренебрегать не всегда, и только до определенного предела. То же и с простотой/сложностью. Если простое решение — неправильное, или работает слишком медленно, что как мы выяснили, тоже является неправильным, то придется применять сложное решение. Насчет хитроумия, функциональный код, как раз, выглядит весьма хитроумно. Ну а безопасность, проистекает из корректности. Корректный код и так должен быть безопасным. А программа, не успевающая обрабатывать запросы — ненадежная.
>Благодаря чистоте функций и неизменяемости состояний, в ФП легче доказать корректность решения.
Это верно только для каких-нибудь математических задач. Дело в том, что для строгой проверки корректности, нужно чтобы требования к программе были сформулированы так же строго. Насколько реально, для прикладных задач, строго сформулировать разумные ожидания пользователя? Как это вообще сделать? Кто должен этим заниматься, и сколько времени это займет? Не будет ли написание обычных юнит тестов быстрее? Что проще, набрать команду толковых тестировщиков, или набрать команду толковых математиков? И кому придется больше платить? Кто докажет, что требования в итоге сформулированы корректно? И кто докажет корректность интерпретатора, выполняющего функциональную программу? Где гарантия, что он одинаково работает на любом железе и при любом окружении, под нагрузкой, с временными задержками и т.д? Все равно, без тестирования, в условиях, приближенных к реальным, не обойтись.
Да и к тому же, сколько лет уже используется императивное программирование? До сих пор корректность работы программ была достаточной, и вполне неплохо проверялась с помощью тестов. Так что, это как минимум, не является острой проблемой, которую только ФП может героически решить. Что же касается научной сферы, где строгая проверка действительно актуальна, а проблемы скорости алгоритмов, наверное не очень критичны, то тут никто и не спорит, что функциональное программирование хорошо для этого подходит. Да и количество математиков на квадратный сантиметр, там побольше будет.
>Мне кажется, ООП — более высокий уровень абстракции
Уровень абстракции у ООП высок на этапе описания предметной области в виде структуры классов. Это, можно сказать, декларативная часть ООП. Описание классов и отношений между ними — декларативно, А код методов императивен. И работа с экземплярами классов происходит в императивном режиме. То есть сочетается сразу два уровня абстракции. Чем лучше мы отразим предметную область в терминах классов, тем более высокоуровневым будет наш код. То есть мы можем варьировать уровень абстракции. Возможно именно поэтому ООП пользуется таким успехом. Но, конечно же, у этого варьирования есть свои пределы. Именно поэтому, код в ОО стиле кажется избыточным в очень маленьких проектах — слишком много лишней декларативщины. И поэтому же, код становится слишком запутанным на очень больших проектах — мы не можем избежать императивного кода, а на большом проекте, накапливается его критическая масса. То есть абстракции, предоставляемой ОО подходом становится недостаточно. В этом плане функциональные элементы хорошо дополняют ОО язык, позволяя уменьшить количество императивного кода в некоторых местах. А те же лямбды помогают не засорять декларативную часть всякими служебными, одноразовыми методами, не имеющими никакого смысла в терминах предметной области. Но эти функциональные элементы не имеют особого отношения к чистому функциональному программированию. Ведь предметная область по прежнему остается описана в терминах классов, а основная часть логики по прежнему описывается императивно.
Но опять же, надо учитывать, что большинство применяемых ОО-языков не являются строго ОО-языками. Они все мультипарадигменные. Так уж получилось, что ОО-парадигма хорошо совмещается с элементами других парадигм. Наверное это вторая причина успешности ООП. Если подумать, из всех ОО-языков, которыми я хоть как-то владею, более-менее консервативным, в плане поддерживаемых парадигм, был только Delphi. При чем именно старый Delphi, в котором даже Generic'ов не было. И что-то я не заметил, чтобы он всем очень нравился. Так что, сколько бы не говорили о засилье ООП, на самом деле, самой популярной парадигмой была и остается мультипарадигменность. Потому что ни одна парадигма в отдельности не является достаточно универсальной, чтобы на ней было удобно делать абсолютно всё.
И эта проблема не является эксклюзивной для функциональных языков. Каждый раз, когда мы поднимаемся на более высокий уровень абстракции, мы теряем в производительности. Но если при этом растет скорость и простота разработки, и вообще появляется хоть какое-то преимущество, всегда найдется сфера применения, где это преимущество окажется важнее недостатков. Вопрос только в том, насколько эта сфера применения будет широка.
И вот исходя из этого и следует определять, где ФП применимо, а где нет. В последнее время просто была тенденция, форсить функциональные языки везде и всюду, как какую-то новую религию. А потом уже и в комментариях на Хабре, на прочих форумах, и вообще в разговорах с другими программистами, я стал замечать, что некоторые видят написание чего-либо в функциональном стиле, как самоцель. Будто если программа написана на функциональном языке, то это ее главное преимущество. Поэтому появление таких вот контр аргументирующих статей вполне закономерно. Такое и с другими новыми технологиями/языками случается. Сначала появляется шквал статей, где какая-то технология описывается, как серебряная пуля. Следом идут статьи, где происходит срыв покровов, и объявляется, что серебро оказалось простой нержавейкой.
Программисты в своей массе вообще довольно «религиозны». Я конечно же имею в виду не традиционные религии, а фанатичное следование каким-либо трендам. Для многих ООП — это настоящая религия. А для других, вот — ФП. Есть те, для кого нет бога кроме MVC. А кто-то делает идола из соглашений по написанию кода. Встречались мне и более экзотические верования, например священный джихад против множественных return'ов из функции. Может и в других профессиях такое наблюдается, но мне почему-то кажется, что программисты, чаще всего участвуют в священных войнах. Проблема еще в том, что у нас это легко может выйти за пределы какого-нибудь форума. У многих есть возможность проталкивать свои идеи на практике. И вот тут надо проявлять осторожность.
И не надо путать частоту использования функции и ее нужность. Сколько раз вы пользовались огнетушителем? Большинство людей ответит: «Ни разу». Так может ну его нафиг? Ведь, 83% огнетушителей никем не используются. Или все же оставим их, на всякий пожарный? А еще, на самом деле, только 1% из 10 000 людей используют контрастные темы в компьютере или смотрят новости с субтитрами. А сколько процентов русскоговорящего населения читают Хабр?
Кто-то может вообще не использовать новую функциональность, а у кого-то весь сервис на ней будет построен. Все потому, что по сравнению со старой, базовой функциональностью, которая была и остается практически необходимым минимумом для создания любого сайта, новая — имеет более узкую, специализированную область применения. Это касается не только самых новых функций, но и тех, что уже успели хорошо прижиться. Едва ли вам удастся реализовать сайт без ссылок. А вот без видео вполне можно обойтись на многих типах сайтов. В то же время ютуб, без возможности встроить в страницу видео, не существовал бы. Вы, конечно, можете сказать, что он прекрасно работал и до появления html5 и тега video. Ну да, работал. На флеше. Вы, кажется, что-то говорили про безопасность? Так вот, чем больше умеет браузер, тем меньше нужны сторонние дырявые плагины.
Конечно, сравнивать какой-нибудь Vibration API с тегом video — не совсем честно. Это просто разные весовые категории. Но с другой стороны, мы всё дальше движемся в сторону создания универсальных web приложений, а это требует существенного наращивания функционала в браузерных движках. Ведь без хорошего запаса по функционалу, в том числе по интеграции с операционной системой и железом, ни о какой универсальности не может идти и речи. Разработчики просто будут предпочитать нативные приложения, в которых можно, и вибрацией управлять, и к датчику освещенности обратиться. Даже если сегодня это не требуется, мне, как разработчику важно знать, что я в принципе смогу это сделать, если от меня потребуют. Да и пользователи, при прочих равных, будут предпочитать приложения, которые подстраиваются под освещенность, и могут вибрировать, при необходимости, например, когда в чате упоминают твоё имя. В конце концов, из таких вот мелочей и строится удобство.
Не совсем понимаю причем тут именно typedef? А что будет если просто имена двух разных классов совпадут? Да ничего не будет. Если они в пределах одного пространства имен, код просто не будет компилироваться.
Вот оно, теперь мне стало ясно, в чем мы друг друга не поняли. Я не предполагал такое количество языков, и что они будут создаваться вообще на каждый чих. Я предполагал, что в виде отдельных языков будут отражены основные парадигмы программирования, и что эти языки можно будет каким-то стандартным образом совмещать. Языки эти будут более-менее чистыми, без излишеств. А так же будут более специализированные языки. Под специализированными языками, я понимал, например, языки для написания бэкенда, для работы с базами данных (на стороне самой БД уже есть SQL, но хотелось бы иметь стандартизированный слой для работы с БД, на стороне клиента, то что сейчас каждый язык делает по своему), для работы с текстом (те же самые регулярки), и т.д. Причем суммарно, разнообразие не увеличится, а уменьшится. То, что существуют регулярки для обработки текста приводит к упрощению, а не к усложнению. Ну и что, что надо выучить еще один «язык»? Зато потом можно применять его везде, а не изучать кучу методов для такой обработки в каждом языке. То же и с SQL. Было бы фигово, если бы каждый язык предоставлял свой синтаксис для запросов к БД. Какие еще вещи выделятся в отдельные языки, я не знаю. Может работа с сетью, а может обработка файлов. В итоге жизнь сама рассудит. Это еще один важный момент, я не призывал к созданию кучи языков, как к самоцели. Я лишь предположил, что это вероятно станет следствием создания единого стандарта, для взаимодействия различных языков программирования друг с другом. И вот это именно то, что я предложил — создать такой стандарт. На мой взгляд, это очевидно приведет к декомпозиции в сфере языков программирования, а вот в какой именно форме это выразится, я не уверен. Возможно будет как я предположил — сильная декомпозиция, а может появится несколько более простых диалектов C# (и других языков), для разных целей. Даже по этой теме мы видим, что все споры в основном сводятся к тому, что один человек не понимает, зачем нужна та или иная особенность языка, а другой ему отвечает, что это применяется там, здесь и еще вот тут. Так может и стоит разделить все эти вещи по разным языкам, раз уж это разные сферы применения? Сейчас этого не делается, чтобы была возможность совместить разный функционал при необходимости. Вот такую возможность и предоставит стандарт взаимодействия языков. А может и этого не будет, а просто будут использовать это для того, чтобы решить проблему обратной совместимости и не тянуть огромное легаси старых версий языка. Да даже если только одна эта проблема будет решена, я буду на седьмом небе от счастья. Чтобы не было больше таких вещей, как модификатор «private protected» в C#, или фигурные скобки вместо присваивания в C++.
Им всего-то надо знать хотя бы один нужный язык, чтобы принести пользу со старта. В крайнем случае, джун сможет быстро выучить нужный язык, и придти устраиваться через неделю.
>Ну вот, собственно, «маленькие» языки имеют ту же самую проблему
Не совсем так. В случае с JS фреймворками, они основаны на JS, который сложнее, каждого из этих фреймворков, и его тоже нужно выучить.
>Вы про какой-нибудь REXX или что-нибудь подобное — много слышали? А с языком 1С общались?
А что не так с REXX? Я так и писал: «в условиях, когда языки легко между собой интегрировать». Когда он поддерживался операционной системой и другими языками, читай, его легко было интегрировать, он был популярен. Сейчас он особо не поддерживается, во всяком случае «из коробки», поэтому о нем забыли. Логика как раз соблюдается. Современной аналогией можно считать регулярные выражения. Несмотря на брэйнфаковый синтаксис, они очень популярны, потому что поддерживаются во многих языках, т.е. легко интегрируемы.
Ну а 1С, он не интегрируется с другими языками, на сколько мне известно. И очень простым его не назовешь.
>Именно потому что «стек технологий» облегчает жизнь джуниору, но усложняет жизнь работодателю, а кто платит — тот заказывает музыку.
А чем именно он осложняет жизнь работодателю? Я тогда вообще ничего не понимаю. Одни работодатели плачутся, что не могут найти себе rockstar c++, другим не нравится система, упрощающая вход для джуниоров. А что же им тогда нужно? Чтобы проект уровня Facebook, могла сопровождать уборщица с минимальным окладом?
Что значит со своим? Собственной разработки? Не думаю что будет все настолько диверсифицированно. Зачем людям делать свой язык, если можно решить задачу с помощью существующих? Ведь написать язык это еще сложнее, чем свой фреймворк сделать. Такое осилят только очень крупные компании, и в условиях, когда языки легко между собой интегрировать, их языки быстро перейдут из разряда «своих», в разряд общеупотребимых. А если кто-то и будет клепать проприетарные языки, похожие на уже существующие, то разве сложно выучить язык, если он простой, и похож на уже существующий, который ты знаешь?
>если язык «хорошо заточен» под определённую область (как какой-нибудь APL), то он оперирует концепциями, которые в других языках выглядят сильно по-другому
Это уже больше относится к изучению новых концепций и парадигм. Сложность тут не от языка зависит. И если такой заточенный язык нужен, его и сегодня создадут, только о совместимости и интеграции с другими могут не подумать. Если же концепция человеку знакома, т.е. он не новичок в предметной области, то изучение такого языка наоборот будет для него естественным. Читая стандарт такого языка, строчку за строчкой, он будет лишь кивать головой и приговаривать: «Ну конечно», «Само собой», «Так и надо», «Я бы тоже так сделал», и т.д.
>если язык реализует известную тебе парадигму», то он, скорее всего, не нужен вообще
Обычно, исторически так складывается, что несколько языков развиваются параллельно, а потом разница у них оказывается в деталях. И «одинаковые» языки продолжают существовать по двум причинам:
1) Кодовую базу терять жалко, начав писать проект на одном языке, нельзя продолжить на другом. Языки хоть и похожи, но не очень совместимы между собой. Если кратко, то легаси.
2) Кому-то могут быть важны вот эти самые детали, различия между языками.
Соответственно я и предполагал, что многие различия уйдут в сопрягаемые миниязыки. И для каждой мажорной парадигмы, со временем, останется небольшое количество языков, либо вообще один язык. И легаси уже не помешает этому процессу. Скорее все же их останется несколько. Некоторые детали не слишком удобно будет выносить отдельно. Но языки будут просты и похожи. Зная один, очень быстро освоишь другой. Образование тоже сможет адаптироваться к этому. Будут специальные учебные материалы, типа: «язык B, для тех, кто знает язык A». Сейчас, я например не смог найти книжку: «Java, для тех кто знает C#». Может дело в том, что отличий все же слишком много, и подобная книга оказалась бы толще, чем мне представляется.
>К сожалению «маленькие языки» делают эту проблему только острее.
То есть вы считаете, что система, которую я описал, когда два джуна, хорошо знающих каждый свой небольшой язык, успешно справляются, каждый со своими небольшими задачами, и параллельно друг друга учат и сильнее погружаются в процесс — не сработает? Можете объяснить почему?
Мне почему-то кажется что должно сработать. Вот даже с сегодняшними реалиями, в компанию, разрабатывающую сайты, приходит человек, знающий только SQL Ведь можно ему поручить писать хранимые процедуры. А параллельно, он будет учиться, не только использовать, но и разрабатывать базы данных. Совершенно независимо от этого, его учат, например, писать регулярные выражения. И вот он уже может писать их, помогая, как в бэкенде, так и во фронтенде. Параллельно он изучает html и css. Изучив, он уже и верстать может. Следом он начинает изучать JS. С последним конечно придется повозиться. Человек постепенно обрастает знаниями, становясь full stack разработчиком. Но вход у него получается плавный, и даже со старта, он был полезен и выполнял реальные «боевые» задачи, зная только SQL. С каким-нибудь навороченным языком, типа C#, проблема в том, что если человек уже освоил основные алгоритмические конструкции, типы данных и структуры, но все еще не въехал в наследование, дженереки, лямбды, делегаты, интерфейсы и LINQ, он почти бесполезен в работе. Даже если сам он уже дорос, чтобы писать простой код, он откроет чьи-то исходники и ужаснется. У меня так было, когда в институте учился. Вроде сидишь, учишь, учишь, по предмету пятерки, курсовые сдаешь, а открываешь «реальный» код, и ничего понять не можешь. У меня вообще такое чувство, что я тот же C# раза четыре выучил, на самом деле. Вообще, любой язык сейчас, приходится учить, минимум дважды. Сначала, ты изучаешь, как на нем писать, в принципе, а потом изучаешь, как писать принято/правильно. Если язык более универсальный, то потом ты еще узнаешь что этих самых «принято/правильно» много разных, в зависимости от области применения. Вот вам и третья итерация изучения. А потом еще идет четвертая — изучение мощного, навороченного фреймворка, под конкретную задачу.
В этом плане, JS переплюнул всех, на мой взгляд. Выучил JS, а как же JQuery? А теперь изучи десять разных способов объявления объекта, и пять способов реализации наследования. Вот теперь ты готов начать изучать язык по настоящему. Angular, React… Постой, постой, зачем ты изучаешь первый ангуляр? Уже пора второй. Хотя знаешь, первый тоже пригодится. В итоге приходишь на работу устраиваться, и тебе говорят: «Ну знаете, пока вы все это учили, вышло пять новых фреймворков, каждый из которых, как отдельный язык, поскольку каждый предполагает свою философию, и написание кода в своем собственном стиле. А еще появилось три новых стандарта языка, и половина тех функций, старых фреймворков, что вы учили, больше не нужны.»
Проблема, на мой взгляд в том, что на работе, в каждый момент времени, требуется знание конкретного фреймворка, но чтобы до него добраться, надо сначала хорошо изучить основной язык, со всем его многообразием и многоликостью, а потом уже только фреймворк. Да еще и разные фреймворки, выполняющие схожие функции, имеют в качестве основы разные языки. Если бы роль фреймворка выполнял простой, специализированный язык, то нужно было бы выучить только его, и он был бы даже проще обычного языка, поскольку не такой универсальный. Особенно это бы чувствовалось, при изучении нескольких фреймворков. Например для изучения asp.net, django и rails, не требовалось бы учить C#, Python и Ruby. А может и вовсе не было бы такого многообразия фреймворков, ведь основное их отличие в том, какой язык положен в основу.
Ну а особенности предметной области учить придется в любом случае, будь то язык или фреймворк. Это мы никак не упростим.
А будет искать специалиста, со знанием и умением применять определенные парадигмы и стили, а конкретный язык разработчик узнает на месте. Язык освоить проще, чем новую парадигму. Особенно, если язык простой.
>Изучение любого языка, даже очень простого — это куда более серьёзная головная боль, чем изучение пары новых фич, добавленных в существующий язык.
Это вы рассуждаете с точки зрения того, кто уже знает язык. В идеале начал его изучение, когда язык только появился. Такой человек растет вместе с языком. Новичок же вообще не знает за что схватиться. Это как раз приводит к дефициту кадров, и к тому, что за ветеранами языка начинается охота, как за единорогом, т.к. порог входа со временем повышается, новичков прибывает все меньше, и знания языка у них неполные, а более опытный разработчик, не только язык знает в совершенстве, но и опыта имеет много. И поскольку это происходит со всеми языками, то специалисту в одном языке трудно перейти на другой, даже чисто психологически, потому что тут ты гуру, а там будешь джуном, с соответствующим статусом и зарплатой. Именно поэтому я и говорю об упрощении отдельных языков, с превращением набора знаний в некий конструктор, который можно постепенно дополнять. И если языки по прежнему будет очень сложно изучать, значит их не достаточно упростили. А вообще, чем больше языков ты знаешь, тем проще изучать новые. Особенно, если язык реализует известную тебе парадигму. К тому же, новичкам тоже будет намного проще. Работодатель сможет взять джуна, который знает пару простых языков, используемых компанией. И этому джуну сразу можно будет давать реальные задачи. Он сразу будет понимать чужой код, написанный до него, и сам может писать так же. А остальной стек языков, будет изучать постепенно, параллельно с работой и под руководством других программистов. Причем, внимание, не обязательно сеньоров. Такой же джун, со знанием другого языка сможет его научить. Они научат друг друга. В этом и суть упрощения, ведь сложность сейчас состоит не столько в том, что надо выучить много всего, а в том, что надо выучить много всего СРАЗУ, а до этого ты бесполезен в продакшене. Если же подмножества используемых технологий имеют четкое разграничение, не нужно знать их все на старте. Можно начать с небольшого стартового набора, и развиваться постепенно. Это как декомпозиция в коде, когда мы разбиваем один большой метод, на несколько маленьких, минимизируя интерфейс между ними.
>Думаете зря Google создал Go?
Говоря о простых языках, я как раз и представлял что-то вроде Go. Точнее некую комбинацию, вот таких простых языков общего назначения, как Go, и более узких небольших языков, которые добавят глубины. Я как-то, пару месяцев назад, взялся его изучать, сделал тестовый проект. В принципе, язык реально выучить за пару дней. И это при том, что там не только синтаксис свой, но и много концептуальных вещей, новых для меня. Конечно, сейчас я успешно забыл, большую часть, потому что нет возможности на практике использовать. Но это не страшно. Появится подходящий проект, просто за день повторю все, и начну писать. Главная проблема Go, на мой взгляд, низкая расширяемость. Нету средств для обобщенного программирования, нету шаблонов. Это позволяет сохранить язык простым, так что это и преимущество тоже. Но и ограничение. Если же будет возможность совмещать его модули с другими языками, такой проблемы не будет. Не хватает универсальности одного языка, дополни его другим. Языки просто перестанут пытаться стать серебряными пулями, а будут просто занимать свои ниши.
В том же Go, кстати есть и пример того, как сопрягать разные языки. Сишные модули транслируются в конструкции, нативные для Go. Что важно, это заложено в стандарт. Сопрягаемость с Си, это то, за счет чего взлетел C++ в свое время. Тогда, ради совместимости, было решено сделать языки похожими. Go показывает другой путь. Языкам не обязательно быть похожими, чтобы быть совместимыми. Нужно лишь стандартизировать способ использования одного языка из другого.
Вообще, может вы и правы, и настолько радикальных изменений, как я описал не будет, но во всяком случае, стандартизация сопряжения языков, даст нам решение проблем обратной совместимости, позволит более быстрое внедрение новых технологий разработки, с сохранением старой кодовой базы, и даст больше шансов новым средствам разработки «взлететь». Существуют же всякие стандарты для операционных систем, тот же POSIX, есть стандартные сетевые протоколы, модель OSI, а как доходит до языков программирования, то кто во что горазд.
Сначала о проблеме, как я ее понимаю, и откуда она на мой взгляд проистекает. Языки со временем усложняются. Это касается всех активно используемых языков. Особенно это заметно на примере языков с долгой историей. Почему так происходит? Причин, как мне кажется, четыре. Во всяком случае основных.
Во-первых, для разных классов задач подходят разные инструменты, а чтобы один инструмент подходил под многие задачи, он должен быть универсальным. Проблемы у всех универсальных инструментов примерно одинаковые: повышенная сложность и меньшая эффективность, по сравнению с узкоспециализированными инструментами. Эффективность зачастую не так критично падает, а вот сложность может расти очень сильно.
Во-вторых, люди стремятся использовать, прежде всего знакомые им инструменты. Особенно учитывая, что наиболее популярные языки довольно навороченные, учить их долго и сложно, а менее популярных — столько, что жизни не хватит, даже примерно их все оглядеть, и неясно что из них выбрать. Это толкает создателей инструментов, делать их все более универсальными. А единственный способ это сделать — наращивать функционал.
В-третьих, разные классы задач пересекаются между собой, так или иначе. Многие решаемые задачи являются составными частями большого проекта. Бывает, что одну подзадачу было бы удобней решить с помощью одного инструмента, а другую — с помощью другого. Но в программировании это означает, что мне удобно было бы часть проекта написать на Си, часть на С#, а что-то на Scala. Возникает проблема — как потом все это совместить? Гораздо удобней в таком случае, если один язык позволяет написать код в разных стилях и с использованием разных парадигм.
В-четвертых, мир быстро развивается, особенно сфера IT, поэтому языкам программирования тоже приходится стремительно развиваться, чтобы не опоздать за прогрессом. А требования обратной совместимости, не позволяют удалить или переделать старое. Можно только добавлять новое. Поэтому в старых языках проблема со сложностью стоит особенно остро. Да и новый функционал выглядит не всегда логично из-за этого. Взять тот же модификатор «private protected» в C#7. Сама идея хорошая, а синтаксис дурацкий. Если же прекращать развивать старый язык и просто делать новый, то возникнет проблема, как совместить старый код, написанный для старого языка с новым кодом. Ну не выкидывать же проверенные и хорошо отлаженные библиотеки. В свое время C++ перетащил в себя кучу архитектурных решений из C, только чтобы быть с ним максимально совместимым. И ведь взлетел, во многом, благодаря этому.
Ну а теперь к предлагаемому мной решению. Функционал естественно должен развиваться. Крупным проектам бывает необходимо совмещать разные подходы для реализации их составных частей, и интеграция должна быть максимально простой. Идти в ногу со временем тоже нужно. Так как же всего этого добиться, не усложняя языки программирования? Ответ на поверхности — нужно создавать много простых языков для разных задач. А чтобы не терять простоту совмещения разных подходов между собой, и возможность использования кода, написанного для других языков, надо сконцентрироваться на том, чтобы эти языки между собой легко стыковались. То есть, чтобы модуль, написанный на одном языке, было так же просто использовать из другого, как если бы они оба были написаны на одном языке.
Сейчас какой основной способ использования кода одного языка из другого? Скомпилировать библиотеку и ее слинковать. Лично мне кажется, что это никуда не годится. Во-первых в разных ОС формат библиотек и методы их линковки разные, во-вторых подключение таких библиотек сложно назвать простым и удобным. Прежде всего проблема в том, что языки не проектируются с расчетом на легкое использование кода друг друга. Вот это и надо исправлять. Нужен простой и современный стандарт, которому должны будут соответствовать языки, чтобы быть взаимно совместимыми. Тот же .Net и так является семейством языков. Надо только развить эту идею до должного уровня. И тогда не придется в один язык пихать абсолютно всё. И об обратной совместимости можно было бы не париться. Представьте, в том же С++, не пришлось бы придумывать использование фигурных скобочек для присваивания, чтобы избежать неявного приведения типов. Просто в модуле указываешь версию языка, и типы перестают неявно приводится при обычном присваивании с помощью знака равно. Что-то на подобие «use strict» в современных версиях JS. Можно было бы даже использовать разные версии компиляторов для старых и новых модулей, чтобы код самого компилятора не усложнялся.
В общем, мне кажется, что будущее за расширяемым семейством простых специализированных языков. По функционалу это будет как один большой суперъязык, но его подмножества будут четко разграничены, и не надо будет учить его весь, а только необходимые тебе части. Сейчас ты не можешь сказать, что знаешь С#, если не знаешь всех его составляющих. К примеру, нужно обязательно знать оба синтаксиса LINQ. Дело не столько в синтаксисе даже, а в том, что все эти синтаксические штуки, про которые написано в статье, предназначены для разных задач, и программирования в различных стилях. Мало кто решает все типы задач, и использует все возможные стили. И работодатель тоже, как правило, не может сформулировать, владелец какого из стилей им нужен. Вот и получается, что многие вещи ты не используешь, но знать их нужно. А держать в голове, то чем не пользуешься, вообще тяжело. Выучить — не проблема. Проблема — не забыть. При дроблении функционала на разные языки таких проблем не будет. Расширяемость, так же будет намного выше, чем у обычного языка. Не будет проблем обратной совместимости. Исчезнет главная проблема новых языков — малое количество готового кода и компонентов. Один и тот же класс задач смогут реализовывать разные взаимозаменяемые языки. Конкуренция языков будет высокой, ведь перейти с одного на другой, для разработчиков будет не сложно. Скорость эволюции языков будет соответствующая. По сути, два разных синтаксиса LINQ, в такой системе могли бы быть разными языками. Распространение получил бы наиболее удобный, а второй — просто исчез. Либо оба заняли бы свою нишу, не мешая друг другу.
В принципе, решаются все четыре описанные проблемы:
1) От слишком универсальных языков, и их сложности, мы уходим.
2) Языки становятся проще, учить их легче, и даже из непопулярного языка можно использовать компоненты, написанные на более популярных.
3) Пересекающиеся задачи пишем на подходящих языках, а потом все стыкуем.
4) С обратной совместимостью проблем нет — несовместимую со старой, новую версию языка, считаем новым языком, а использовать старый код из нового — не проблема, уж если разные языки совмещаем без проблем.
>помогают
>без нанесения особого вреда окружающим
Вся проблема в том, что именно такая комбинация бывает в исчезающе малом количестве случаев. Вообще, я ни разу такого не встречал, просто умом я делаю небольшое допущение, что может быть это все таки возможно. Но «сердцем» я в это не верю. Уж слишком сильно алкоголики отравили мою жизнь. И нет, речь не только о крепких напитках. Самое обычное пиво пробуждает в некоторых людях неслабую агрессию. Может это и не повод запрещать алкоголь, но с алкоголиками нужно активно бороться, чего, на мой взгляд, не происходит в моей стране. Это кстати очень хорошо показывает, насколько лицемерна наша власть, и всякие подлые Мизулины. Сколько всего они сегодня запрещают, чтобы «защитить детей». Все это ложь. Я был ребенком, и невыносимо страдал от алкоголиков. И никто меня не защитил. И сегодня, миллионы таких же детей, никто не защищает. Ведь нарисованные порнокартинки, по мнению власти, куда опаснее для детей, чем бухой папаша. Конечно, можно сказать, что проблема в людях. Вот только таких людей ну очень много, и проблем от каждого из них тоже очень много. И если бы не алкоголь, от этих самых людей, проблем было бы гораздо меньше. Не может адская машина работать без топлива.
И если уж попытаться отстраниться от эмоций, можно попытаться сравнить статистику, сколько тяжких преступлений совершается на почве алкоголя, а сколько из-за сладкого, жирного, острого, телевизионных сериалов, ток-шоу, аниме, комиксов, компьютерных игр, любительского спорта. Думаю, даже если все остальное вы сложите вместе, алкоголь победит с ошеломляющим перевесом. Еще более показательно будет, если вычесть из статистики те случаи, когда суд признал преступника невменяемым. Псих может по любой причине вытворить что-то ужасное, так что случаи с ними не являются показательными.
З.Ы. Прошу прощения за негатив. Слишком уж болезненная тема для меня.
Академики конечно же не дураки, и будь перед ними инженерная задача, они бы ее решили не хуже инженеров. Ну может на чем-нибудь и набили шишек с непривычки. И в итоге предложили бы вполне себе инженерное, а вовсе не академическое решение. Просто обычно они решают совсем другие классы задач. Задачи академические, и решения академические. Например, доказать, что решения нет, в их случае тоже результат. От инженера, такого ответа никто никогда не примет. Если начальство сказало нарисовать прямую линию в форме котёнка, инженеру придется как-нибудь изловчиться. Ведь он же эксперт.
Что касается требования открыть конкретно одну банку, подобного рода проекты обычно всегда, либо вырастают в более крупные, либо становятся составной частью более крупных проектов. По крайней мере, мой опыт именно таков. Возможно так бывает не везде.
З.Ы. Про трату времени на комбайн ответил ниже по ветке. Если кратко, то я не предлагал создавать комбайн, а лишь использовать готовый.
Да и говоря про комбайн, я не имел в виду бросаться пилить свою собственную вундервафлю. Речь же шла не про создание тапок, ложек, консервных ножей или комбайнов, а про их использование. Так что, исходя из контекста, под комбайном я предполагал использование какого-то готового мощного фреймворка или библиотеки, с расчетом что мелкая задача будет расти, и фреймворк перестанет быть излишним. Собственные комбайны, наоборот, обычно возникают от того, что кто-то начал делать проект на коленке, не оценив его перспектив, затем вовремя не спохватился, чтобы все переписать, и по мере роста проекта, применяемые в процессе костыли разрослись настолько, что стали «фреймворком».
Устная речь в принципе менее строга, чем письменная. Она подвержена, как региональной дифференциации, так и временным флуктуациям. Поэтому письменная речь не должна оперативно подстраиваться под устную. Только если какая-то норма закрепилась достаточно прочно, и ее придерживается подавляющее большинство, можно закреплять эту норму в письменности.
Позволю себе с этим не согласиться. Отличия есть, и они существенны.
1. Свойство нельзя передать по ссылке.
int Val = 0;
int PropVal {get;set}
void ChangeValue(ref int val){val=5;}
…
ChangeValue(ref Val); //работает
ChangeValue(ref PropVal); //ошибка компиляции
Что это означает для нас? Прежде всего то, что мы не можем в будущем заменить публичное поле, на публичное read/write свойство, не сломав обратную совместимость нашего кода. Ведь тот, кто наш код использовал, вполне мог передавать это поле по ссылке, и тогда его код перестанет компилироваться. Так что, если вдруг нам понадобилось добавить немного дополнительной логики к чтению/записи данного поля, например добавить событие на изменение значения, мы уже не сможем так просто этого сделать. Сделав же изначально, свойство вместо открытого поля, мы оставляем себе пространство для маневра.
2. Интерфейсы не могут содержать полей, только методы и свойства. Так что тут у нас и выбора особого нет. Если мы хотим в интерфейсе отразить возможность полного доступа к каким-то данным, нам придется использовать свойство. А поскольку надо сохранять единообразие кода (нам не нужно, чтобы код, являющийся частью интерфейса, сильно выделялся по сравнению с остальным), в объектах тоже имеет смысл использовать свойства. К тому же, все что имеет модификатор доступа, отличный от private — является частью интерфейса нашего класса. А значит, по хорошему, должно соответствовать требованиям, предъявляемым к интерфейсу: никаких полей, только методы и свойства.
Вообще пример с тапком и ложками может и не самый удачный. Это просто мем, на самом деле, который частенько мне вспоминается, когда я слышу предложение, делать что-то с помощью неудобных инструментов. Более правильным примером была бы попытка построить многоэтажный дом, используя только кирпичи, цемент и мастерок.
Что же по поводу использования электрических комбайнов, то зачастую это бывает излишним, да. Но если мне надо открыть не одну консервную банку, а несколько тысяч, консервный нож мне уже не подойдет. Хотя им и можно открыть каждую из банок в отдельности, но чтобы открыть тысячу в разумные сроки, нужен комбайн. И даже если сегодня мне поставили задачу открыть именно одну банку, чутье инженера подсказывает, что как только я эту задачу закончу, далее от меня потребуют открывать миллион банок в минуту. Поэтому, пока найденное мной решение не будет хоть в какой-то степени масштабируемым, я не пойду докладывать, что задача выполнена.