Можешь кратко объяснить его преимущества? Потому что у меня был только курс, посвящённый фортрану, а позже я помогал делать задания по фортрану. Дальше у меня не появилось желания с ним работать. Я признаю, что по скорости фортран неплох, но что касается остального, то для меня он показался очень неудобным.
Я на фортране не писал, его не особо жалую, и вообще, мопед не мой.
В фортране работа с памятью и всякими указателями (или что там вместо них) проще и менее универсальная, чем в C/C++. Поэтому компилятор может более агрессивно оптимизировать код, чем на сишечке, потому что на сишечке согласно стандарту вообще почти любая хуета может быть.
Пример:
void foo(double* a, doube* b)
{
for(...)
{
... some weired shit ...
}
}
Массивы a и b спокойно могут пересекаться, поэтому компилятор, в общем случае, не имеет права векторизовать цикл. Ему надо будет подсказать, что они не пересекаются разными прагмами или еще чем-то. В фортране этого быть не может, поэтому компилятору проще оптимиизровать.
Java настолько мертва, что ныне обновления языка выходят каждые полгода, постоянно обрастает новыми технологиями и свежими версиями популярных фреймворков.
Уже шесть лет как, и то и другое. С чего вы взяли что я выше писал о настоящем?
Но про "тимлид сказал" я писал не в смысле что "я лучше начальника знаю", а в том, что проект с ООП на пур си очень сильно зависим от соглашений о коде, которые кроме как в головах нигде не формализированы, что не особо удобно, особенно когда проект большой.
Я не так давно писал по работе под девайс с несколькими _кило_байтами оперативы(хотя вообще пишу на жабе и скале). Без операционки, естественно, потому хуй вам, а не аллокатор памяти. Смысла юзать плюсы, колхозить аллокатор, да и вообще выделять память под кучу, вообще не было при таких ресурсах, на голом с все прекрасно написалось(все объекты на стеке), и работает по сей день.
Ну и мудрец с картинки кривит душой, ничего вот прямо ТАКОГО в с/с++ нет, если ты не monkey-coder, не имеющий представления, во что это все компилится и как работает на низком уровне.
На С++ никто не заставляет использовать кучу, исключения и выделять память. Но все равно у него остаются преимущества. ООП (без виртуального наследования) ничего не стоит, алсо можно вообще дико ебашить на темплейтах вообще zero-overhead (например. Хотя по мне изврат, да и нынче проще можно) и перегрузка функций. Поэтому я считаю, что плюсы в эмбед норма и вообще мастхэв.
Для этого нужно иметь хороший опыт с плюсами. В частности, в использовании либ - хорошо понимать, что в таких случаях можно, а что нет, да и с самими возможностями плюсов быть аккуратным. Я джавист, до этого проекта на плюсах писал лет 12 назад, и то что-то некоммерческое. Мог наворотить хуйни, и понимал это. С чистым С в этом плане лучше, ибо он простой.
Ну и так, чтобы понимать, что джависты разные бывают. Сейчас вот проект. Средняя нагрузка - 18000 запросов в секунду. Пик - 50-60 тысяч. Обслуживает это дело две ноды, плюс вспомогательная для отложенных тасков(ну и 12 нод редиса, 12 нод перконы, 18 нод гринплама, но они в основном, как и вспомогательная нода, для бэкенда, статистики и прочей хуеты). У меня было 1.5 месяца на оптимизацию, когда пошел трафик. Поначалу обе ноды загинались(средние виртуалки на средних ксеонах), да и основная бд чувствовала себя хуево. Чистка кода, оптимизация кода под jit, тюнинг gc, тюнинг jit(аггрессивный инлайнинг, лимиты на инлацн и глубину компиляции, и прочие штуки), выброс нахуй пиздоватых либ, и... При 18000 запросов в секунду памяти занято меньше гига, процессор загружен на 5-9% на каждой из нод. Пики переживаются легко. Ах, да, нужно перегружать это дело пореже, ибо первые минут 10 после перезагрузки треды jit грузят проц на 100%.
Там сразу дороги расходятся.
Си - обрастаешь волосами, приобретаешь очки (без них продвижение невозможно), за время квеста получаешь +5 к интеллекту и +3 к технологиям. Рандомно минусуется социализация.
По пути С++ очень много рандома прописали. Иногда плюс в математику выпадает, иногда в алгоритмы, стабильно только +2 к интеллекту. Дропается дофига книг, но половина не дает никаких прибавок. Почти никогда не падает социализация, иногда даже повышается. И ветку Карьера тоже можно развивать.
Короче, каждому свое.
Яхз, почему бытует мнение о сложности ассемблера. Это самый простейший из всех языков. Проще просто некуда. Десяток-другой различных команд, полсотни их вариаций с разными аргументами, пара десятков типовых конструкций и все - пиши чего хочешь.
Нет, серьезно, это самый простой и очевидный язык.
Освоить его действительно легко. А вот думать на его уровне сложно. Вот представь что ты собака, у тебя есть лапы, хвост, ты можешь лаять. А теперь объясни человеку что ты - летчик дальней авиации.
Разумеется, для ряда задач ассемблер будет неудобен, а решения на нем будут громоздки, но это справедливо в отношении практически любого языка. Многое зависит от имеющихся своих и внешних библиотек, к примеру, в случае DoS прерывания 10h и 21h умели делать практически все, что было необходимо - работа с файловой системой, ввод/вывод, переход в графический режим и работа с ним.
Ассемблер очень хорошо для понимания как вообще железка работает. Кто понял ассемблер уже не будет мучаться с пониманием что такое указатели в Сях и как работает их арифметика. Но прикол в том, что при написании на ассемблере приходится выполнять просто громадное количество самых базовых операций, который неизбежно будут повторяться помногу раз в программе, из-за чего ты их неизбежно оформишь либо макросом, либо процедурой. И вот твоя программа на ассме уже чуть менее чем полностью состоит из макроассемблерных вставок. Что называется, поздравляю чувак, ты изобрел C.
В свое время в качестве курсача по асму запилил программу под винду на MASM. Ну реально, там стопицот макроопределений, уже даже конструкции вроде if определены, что программа все меньше походит на асм, а все больше на C.
Что интересно, так оно и работает. Асм -- абстракция над процессорным кодом. Наиболее логичная абстракция над асмом -- С или похожий язык. Тот же PHP уже абстракция над C. Своего рода эволюция.
это и есть основной критерий качества языка. хелловордл легко пишется на чем угодно, важно то, насколько долго можно тянуть большой проект на том или ином языке
Ну, на асме просто нет смысла писать целиком проект. Сейчас его обычно используют в качестве вставок для суперкритичного по производительности кода. Причем, как правило, это достаточно линейные числодробилки, писать которые на асме не сильно сложнее, чем на с или той же жабе. Асм там для принудительного использования регистров в основном, чтобы не дергать медленную оперативу в каждой итерации цикла, ну и прочих совсем низкоуровневых оптимизаций.
Хаскель - функциональный язык. Там все функции - функции в математическом смысле, т.н. "чистые", т.е. не имеют побочных эффектов. Вся программа по-сути одна здоровая комбинация функций. Циклы заменяются рекурсией, но компилятор хвостовую рекурсию оптимиизирует, поэтому не бойся за свой стек. Алсо всякая адская система типов. В общем, воплощение матана. Лямбда-исчисление + теория категорий.
Нет, не совсем так, функции не все чистые, есть с побочными эффектами, но они и всё, что их вызывает, тэйнтится соответствующей монадой и не может работать с "нечистыми" значениями напрямую. Получается, что чистые функции всегда можно отличить от нечистых (если ты не используешь unsafePerformIO), что позволяет компилятору творить ебанутые агрессивные оптимизации, а программисту - легко запускать кучу всякого дерьма в параллельных потоках, не парясь о синхронизации (правда, учитывая херовость многопоточного сборщика мусора, который будет сосать член, как ты его ни настраивай, даже нормально распределив нагрузку по ядрам, толк из этого извлечь можно не всегда).
Но хаскелль все равно охуенен. Я пиздец люблю на нем писать. С каждой написанной функцией чувствую себя умнее! И самое крутое - если ты не творишь всяких непотребностей типа симуляциии памяти через Data.Map, чтобы делать "референсы", то просто понимая, что ты пишешь, и добившись того, чтобы код скомпилился, ты уже практически гарантировал корректную работу кода. Но у этого есть и обратная сторона - если баг таки появился, отлаживать сложную прогу на Хаскелле ты ЗАЕБЕШЬСЯ
Пытаясь освоить Haskell искал опенсорсные проекты, где мог попытаться разобраться и улучшить понимание. Так вот проблема была в том, что постоянно натыкался на использование этой самой IO монады и не мог понять это прям вот жизненная необходимость постоянно ее использовать или большинство разработчиков на нем просто нихуя не понимают как писать на функциональном ЯП. Если первое, то нахуя его вообще юзать?
Смотри, прикол Хаскелля в том, что, в отличие от большинства других функциональных языков, в нем нету простого и легкого способа взять и запихнуть в функцию побочный эффект. Тогда как всякие лиспы и окамлы просто поощряют написание кода в функциональном стиле, Хаскелль стремится превратить использование любого сайд-эффекта в сущий ад. И на то есть вполне весомые причины.
Функциональные языки происходят от лямбда-исчисления, модели исчисления, эквивалентной машине Тьюринга. Тогда как машина Тьюринга завязана на переходах из одного состояния в другое и сохранении состояния в ленте данных, в лямбда-счислении это заменяется тем, что функции могут принять на вход данные в состоянии A, и вернуть данные в состоянии B.
"Идеальный" чисто-функциональный язык работает точно так же. В нем по определению нет вообще никаких побочных эффектов. Ты все так же можешь изменять состояние по ходу вычислений, но это состояние должно строго контролироваться, оно всегда будет в параметрах и возвращаемом значении всех функций, что его изменяют. То есть если ты хочешь изменить массив xs, ты обязан сделать let xs = func xs, у тебя нет возможности, например, передать его в функцию по референсу или указателю. Это выглядит муторно, но на самом деле это охуенно. Каждая чистая функция идемпотентна, и из-за этого ее гораздо легче написать правильно. Более того, это открывает целый мир возможностей хитрого чейнинга функций через всякие хитрожопости типа map, foldr и так далее, что позволяет писать короткий, красивый и понятный код. Это настолько удобно, что такие плюшки из функциональных языков начали пихать и в популярные нефункциональные языки - например, Optional в джаве с чейнингом map, или вся эта реактивная хренотень в джаваскрипте с Observable-ами. Еще тебе внезапно становится охрененно удобно и полезно пользоваться каррированием - это когда ты можешь передавать в функцию не все агрументы сразу, я не буду про это писать здесь, но это очень важно, почитай про это. Еще очень крутое преимущество - ленивое исполнение, грубо говоря, ты можешь исполнять какие-то вычисления только тогда, когда они понадобятся, что иногда позволяет очень сильно оптимизироать код, например, когда ты долго высчитываешь каждый элемент массива, а потом тебе нужно найти в нем первое значение, соотетствующее условию - ты можешь отдельно заполнить весь массив, отдельно искать, сэкономив кучу кода и гемора, и лишней работы все равно не будет сделано. У этого есть еще один бонус - этот массив может быть хоть бесконечным, если тебе не надо проходиться по нему до конца, то это ни на что не влияет. У чистоты есть и другие преимущества - ты можешь параллелизировать сколько твоей душе угодно, и все это потому, что идемпотентным чистым функциям вообще поебать на порядок исполнения. И компилятор может за милую душу менять порядок исполнения всего, чего хочет, и делать common subexpression elimination (удаление общих подвыражений) на вызовы функций, функций, Карл! Ах да, и раз тут уже такие дела, надо упомянуть, что это помогает делать язык крайне униформным, и в результате легко сделать так, что в таком языке все будет функцией (как в питоне все - объект). Арифметический оператор? Функция! Значение? Функция без параметров! Даже фигню типа целых чисел можно определить из начальной функции и функции-successor-а, это называется числа Пеано, почитай, если интересно.
Так вот, к чему это я. Все это хорошо, но это не практично. Идеальный чисто функциональный язык возможен, но хрен пойми, как им пользоваться. Единственный разумный вариант - сделать в нем функцию main, аргументы в которую будут поступать с командной строки, чтобы это были единственные входные данные, которые может получить программа. Но это тупо! Наши программы работают в императивной среде ОС, где постоянно могут происходить какие-то события. Нахрена тебе программа, которая только и может, что получить на вход данные и высрать результат, как одна большая функция? А если ты хочешь написать GUI, или хотя бы консольный UI с хоть каким-то интерактивным взаимодействием с пользоваталем? А если ты хочешь сделать байндинги до кода на любом другом языке? Для всего этого нужны побочные эффекты! Большинство функциональных языков для решения этой проблемы просто добавило дополнительный синтаксис для изменения переменных, который типа не рекомендуется использовать. Но Хаскелль пошел дальше.
Хаскелль создал нечто уникальное - систему для императивного программирования внутри (практически) чисто функционального языка. Монада - это интерфейс (в Хаскелле они называются тайпклассами), описание типа данных. Типы данных в Хаскелле, как и в других функциональных языках, работают как "контейнеры", в которых может лежать какое-то значение или значения другого типа. Монада описывает тип данных, который держит в себе значение/значения одного типа (с помощью каррирования можно сделать больше, чем одно, как в монаде Either, но это не важно). Для этого типа данных должны быть определены функции, позволяющие делать композицию работающих с этой монадой функций. Причем эта композиция будет гарантировать исполнение этих функций в строгой очередности, просто потому, что они определены так, что каждой следующей из сложенных композицией функций будет необходимо, чтобы была исполнена предыдущая. Используя этот чейнинг и синтаксический сахар для него под названием do-нотация, ты можешь фактически писать императивный код, не нарушая никаких принципов написания чисто функционального кода.
Монад в Хаскелле много. Maybe, [] (list), Either, да дохрена их. Если тебе понадобилось положить значение в монаду, ты можешь с ним работать, используя все функции монад (и функторов, про них тоже почитай, и еще почитай про аппликативы, большинство монад так же аппликативы), включая в себя do-блоки. Но ты в любой момент можешь вытащить из таких монад значени(я), что в них леж(а)т. Но это справедливо не для всех монад. Есть монады IO, которые абстрагируют настоящие побочные эффекты. Вытащить из них значение невозможно безопасным образом, потому что функция перестанет быть идемпотентной! Но пока значение висит внутри монады, ее можно рассматривать как черную коробку, в которой хрен пойми что лежит. И если функция хочет работать с таким значением и как-то его доставить в возвращаемое значение, то эта часть возвращаемого значения должна стать тоже эдакой черной коробкой. И получится, что если закрыть глаза на все такие черные коробки и представлять, что нам пофиг на то, что в них лежит, то все такие функции останутся с грехом пополам идемпотентными. Конечно, они уже не будут чистыми, их нельзя будет так просто параллелизировать и лениво исполнять, но их можно будет все точно так же использовать в императивном контексте, например, do-нотации. Каждый do-блок теперь можно превратить в маленькую императивную программу, которая будет, например, делать какое-то интерактивное I/O. В зависимости от результатов этого I/O оно сможет вызвать какую-нибудь чистую функцию, но результат вычислений в этом блоке всегда будет лежать в IO монаде, и все, что его использует, должно будет так же "тейнтить" полученные от него по цепочке вызовов значения, и все такие функиции перестанут быть чистыми, но будут юзабельными во всяких do-блоках. И в конце концов все это докатывается до мейна, у которого тип... main :: IO ().
Вот так вот. По-моему, это гениально, и совершенно охуенно. Обожаю Хаскелль. Дай бог я нигде в этой стене текста не ошибся
Во-первых, не идёт это ни с чем вразрез, Хаскелль был рассчитан на использование IO, это неотъемлемая часть языка, а не приколоченная сбоку поебня, как в некоторых других языках.
Что до обилия IO, то при хорошем написании кода бизнес-логика будет вся чистой. При помощи всяких мэпов, байндов, лифтов и так далее можно легко использовать чистые функции в монадических вычислениях.
Вообще по-хорошему IO должно быть либо там, где есть какое-то прямое взаимодействие со страшным императивным миром за пределами программы, либо в какой-то функции, которая высчитывает что-то, использующее напрямую полученное из IO значение. При этом это значение может быть через fmap прогнано через вполне себе чистую функцию, которая все посчитает, но вернуть все надо будет в любом случае в монаде.
Это, кстати, еще и хороший способ разделить основную логику приложения от взаимодействия с окружающей средой, типа separation of concern. Второе будет в тэйнтнутых какой-нибудь IO-монадой функциях, доходящих по небольшой цепочке вызовов до мэйна, а первое - во всех чистых функциях, которые они вызывают.
не можешь запомнить несколько синтаксисов, и принципов работы с несколькими языками?
не пойми превратно, PHP и язык 1C тоже считаю недоязыками программирования. хотя сам 1с-Программист и веб разработчик. Но проблем с С++ не наблюдаю.
Я может не так тебя понял и ты вообще всю теоретическую электорнику называешь Булевой алгеброй. Просто все кого я из области знал, включая себя с освоением этой сложной и не посильной наукой справлялись за минут десять.
Ну не совсем, булевая алгебра чуть пошире, правила де Моргана там всякие, оптимизации и прочее. Так что за 10 минут вряд ли разберешься. Вообще я бы чуть пошире копнул - дискретная математика нужна.
Ну в Дисциплинах ВУЗов всё, что связанно с бинаркой, но не было описано в шуточной математике Буля, т.е. Таблицы истинности, Карно карты, сокращения и пр., является уже "цифровая электроника", где Булева алгебра это только одна лекция всего курса. Название конкретно предмета может быть разным в ВУЗах, но в моём было Основы теоретической электроники.
У нас это было в "Дискретной математике". Карты Карно и прочее действительно всплывали потом в Схемотехнике и т.п. Однако теория графов и т.п. была только там.
1) Много строк != Плохо. iostream состоит из шаблонов чуть более чем полностью. Все эти строки ничего не стоят после компиляции. You don't pay for what you don't use
2) Количество строк зависит только от того как разработчики компилятора реализовали библиотеку
Ну ты бы годик еще подождал, а потом коммент написал.
Так то оно все верно. You don't pay for what you don't use - плюсы именно за это и любят. Единственная проблема, это то, что иногда крупные проекты компилятся ну очень долго.
Интересный у тебя юзернейм на винде, а не тян ли ты случаем?
Это значает что функция не принимает никаких аргументтов.
В плюсах int main() и int main(void) одно и то же. Никакой разницы нету.
В С разница большая. Пустой список аргументов (без void) означает, что принимаемые аргументы не указаны и функция может принимать в качестве аргумента что угодно. Если стоит void, это означает, что функция не принимает никаких аргументов.
а если таки задать аргумент, то выдаст ошибку или проигнорирует аргумент?
int main(void){ ... }
main(42);
я просто с js пришёл, там всякую хуйню творить можно
Да, В С если таки задать аргумент, то такое скомпилится и возможно даже будет работать просто игнорируя аргумент. Но это Undefined Behaviour т.е. последствия могут быть непредсказуемые
В плюсах будет ошибка при компиляции в любом случае.
Я в двух словах попытаюсь объяснить почему так.
В С и С++, каждые .c / .cpp файл (называется translation unit) компилится полностью независимо друг от друга. Поэтому если код какой-то функции присутсвует в одном файле (это назвается определение или definition), но использовать ее нужно в другом, то нужно предоставить т.н. объявление (declaration) функции. Когда компилится файл с определением функции, то в объектные файл добавляется код функции с ее именем (символом). Объявление функции позовляет ее использовать без наличие самого кода (определения). Обычно Declaration пишут в хедерах, и оно является просто указанием компилятору, что где-то есть такая функция с таким именем. Во время линковки это дело сшивается в одно целое и если какую-то функцию наяти не удалось, случается ошибка линковки.
Разница между С и С++ тут в том, что в С символ функции это просто ее имя. Т.е. линковщих не может никак проверить какие аргументы эта функция принимает. Следовательно и объявить функцию можно не зная какие аргументы она принимает, поэтому отсутствие аргументов означает, что неизвестно какие аргументы она принимает.
В С++, символ состоит не только из имени, но и из сигнатуры, поэтому перепутать две функции никак не получится. Это сделано чтобы можно было перегружать функции, при этом генерирую обычные С совместимые объектные файлы которые можно залинковать вместе. Символ функции формиркется из ее имени и сигнатуры особым образом который называется name mangling, поэтому при обявление нужно указывать какие аргументы она принимает всегда. Следовательно, обявление без аргументов это просто функция которая не принимает аргументов.
Выбор языка программирования
Начнем с простого. Вы блядь?
а
Нет
У вас есть друзья в реальной жизни?
а
Они тоже бляди?
а
' И
ет
Java
C++
Даун?
Haskell
а
РНР
Нет
А аниме смотрите?
Н
ет
Ruby
Превосходно! Осталось лишь узнать какие приложения вы собираетесь разрабаты
Даже фортран будет жив ещё долго.
В фортране работа с памятью и всякими указателями (или что там вместо них) проще и менее универсальная, чем в C/C++. Поэтому компилятор может более агрессивно оптимизировать код, чем на сишечке, потому что на сишечке согласно стандарту вообще почти любая хуета может быть.
Пример:
void foo(double* a, doube* b)
{
for(...)
{
... some weired shit ...
}
}
Массивы a и b спокойно могут пересекаться, поэтому компилятор, в общем случае, не имеет права векторизовать цикл. Ему надо будет подсказать, что они не пересекаются разными прагмами или еще чем-то. В фортране этого быть не может, поэтому компилятору проще оптимиизровать.
https://habr.com/post/403037/
порвали два боянанаписали три стандарта.(Точнее по новой версии раз в 3 года, начиная с 2011).
Даже у паскаля (free pascal) последнее обновление было меньше года назад.
УМИРАЕТ! ЗАБУДЬ ЭТОТ ЯЗЫК ЕМУКАПЕЦ! БОЛЬШЕ НИКТО НИКОГДА НА НЁМ НИЧЕГО НЕ НАПИШЕТ!
Оба языка живее живых, у них немного разные (хоть и пересекающиеся) сферы применения, С++ не является полной заменой С.
Where is your god now?
Говорю как человек долго ипавшийся с проектом в ООП на Pure C.
Одна только инкапсуляция на уровне синтаксиса а не ОдинТимлидСказалПисатьТак (а если не так то все валится к чертям) уже многого стоит.
Но про "тимлид сказал" я писал не в смысле что "я лучше начальника знаю", а в том, что проект с ООП на пур си очень сильно зависим от соглашений о коде, которые кроме как в головах нигде не формализированы, что не особо удобно, особенно когда проект большой.
Ну и мудрец с картинки кривит душой, ничего вот прямо ТАКОГО в с/с++ нет, если ты не monkey-coder, не имеющий представления, во что это все компилится и как работает на низком уровне.
Си - обрастаешь волосами, приобретаешь очки (без них продвижение невозможно), за время квеста получаешь +5 к интеллекту и +3 к технологиям. Рандомно минусуется социализация.
По пути С++ очень много рандома прописали. Иногда плюс в математику выпадает, иногда в алгоритмы, стабильно только +2 к интеллекту. Дропается дофига книг, но половина не дает никаких прибавок. Почти никогда не падает социализация, иногда даже повышается. И ветку Карьера тоже можно развивать.
Короче, каждому свое.
Нет, серьезно, это самый простой и очевидный язык.
В свое время в качестве курсача по асму запилил программу под винду на MASM. Ну реально, там стопицот макроопределений, уже даже конструкции вроде if определены, что программа все меньше походит на асм, а все больше на C.
Судя по этому комиксу, я вышел из той пещеры? и ушел в пыху...
Я не очень умный.©
Но хаскелль все равно охуенен. Я пиздец люблю на нем писать. С каждой написанной функцией чувствую себя умнее! И самое крутое - если ты не творишь всяких непотребностей типа симуляциии памяти через Data.Map, чтобы делать "референсы", то просто понимая, что ты пишешь, и добившись того, чтобы код скомпилился, ты уже практически гарантировал корректную работу кода. Но у этого есть и обратная сторона - если баг таки появился, отлаживать сложную прогу на Хаскелле ты ЗАЕБЕШЬСЯ
Функциональные языки происходят от лямбда-исчисления, модели исчисления, эквивалентной машине Тьюринга. Тогда как машина Тьюринга завязана на переходах из одного состояния в другое и сохранении состояния в ленте данных, в лямбда-счислении это заменяется тем, что функции могут принять на вход данные в состоянии A, и вернуть данные в состоянии B.
"Идеальный" чисто-функциональный язык работает точно так же. В нем по определению нет вообще никаких побочных эффектов. Ты все так же можешь изменять состояние по ходу вычислений, но это состояние должно строго контролироваться, оно всегда будет в параметрах и возвращаемом значении всех функций, что его изменяют. То есть если ты хочешь изменить массив xs, ты обязан сделать let xs = func xs, у тебя нет возможности, например, передать его в функцию по референсу или указателю. Это выглядит муторно, но на самом деле это охуенно. Каждая чистая функция идемпотентна, и из-за этого ее гораздо легче написать правильно. Более того, это открывает целый мир возможностей хитрого чейнинга функций через всякие хитрожопости типа map, foldr и так далее, что позволяет писать короткий, красивый и понятный код. Это настолько удобно, что такие плюшки из функциональных языков начали пихать и в популярные нефункциональные языки - например, Optional в джаве с чейнингом map, или вся эта реактивная хренотень в джаваскрипте с Observable-ами. Еще тебе внезапно становится охрененно удобно и полезно пользоваться каррированием - это когда ты можешь передавать в функцию не все агрументы сразу, я не буду про это писать здесь, но это очень важно, почитай про это. Еще очень крутое преимущество - ленивое исполнение, грубо говоря, ты можешь исполнять какие-то вычисления только тогда, когда они понадобятся, что иногда позволяет очень сильно оптимизироать код, например, когда ты долго высчитываешь каждый элемент массива, а потом тебе нужно найти в нем первое значение, соотетствующее условию - ты можешь отдельно заполнить весь массив, отдельно искать, сэкономив кучу кода и гемора, и лишней работы все равно не будет сделано. У этого есть еще один бонус - этот массив может быть хоть бесконечным, если тебе не надо проходиться по нему до конца, то это ни на что не влияет. У чистоты есть и другие преимущества - ты можешь параллелизировать сколько твоей душе угодно, и все это потому, что идемпотентным чистым функциям вообще поебать на порядок исполнения. И компилятор может за милую душу менять порядок исполнения всего, чего хочет, и делать common subexpression elimination (удаление общих подвыражений) на вызовы функций, функций, Карл! Ах да, и раз тут уже такие дела, надо упомянуть, что это помогает делать язык крайне униформным, и в результате легко сделать так, что в таком языке все будет функцией (как в питоне все - объект). Арифметический оператор? Функция! Значение? Функция без параметров! Даже фигню типа целых чисел можно определить из начальной функции и функции-successor-а, это называется числа Пеано, почитай, если интересно.
Так вот, к чему это я. Все это хорошо, но это не практично. Идеальный чисто функциональный язык возможен, но хрен пойми, как им пользоваться. Единственный разумный вариант - сделать в нем функцию main, аргументы в которую будут поступать с командной строки, чтобы это были единственные входные данные, которые может получить программа. Но это тупо! Наши программы работают в императивной среде ОС, где постоянно могут происходить какие-то события. Нахрена тебе программа, которая только и может, что получить на вход данные и высрать результат, как одна большая функция? А если ты хочешь написать GUI, или хотя бы консольный UI с хоть каким-то интерактивным взаимодействием с пользоваталем? А если ты хочешь сделать байндинги до кода на любом другом языке? Для всего этого нужны побочные эффекты! Большинство функциональных языков для решения этой проблемы просто добавило дополнительный синтаксис для изменения переменных, который типа не рекомендуется использовать. Но Хаскелль пошел дальше.
Хаскелль создал нечто уникальное - систему для императивного программирования внутри (практически) чисто функционального языка. Монада - это интерфейс (в Хаскелле они называются тайпклассами), описание типа данных. Типы данных в Хаскелле, как и в других функциональных языках, работают как "контейнеры", в которых может лежать какое-то значение или значения другого типа. Монада описывает тип данных, который держит в себе значение/значения одного типа (с помощью каррирования можно сделать больше, чем одно, как в монаде Either, но это не важно). Для этого типа данных должны быть определены функции, позволяющие делать композицию работающих с этой монадой функций. Причем эта композиция будет гарантировать исполнение этих функций в строгой очередности, просто потому, что они определены так, что каждой следующей из сложенных композицией функций будет необходимо, чтобы была исполнена предыдущая. Используя этот чейнинг и синтаксический сахар для него под названием do-нотация, ты можешь фактически писать императивный код, не нарушая никаких принципов написания чисто функционального кода.
Монад в Хаскелле много. Maybe, [] (list), Either, да дохрена их. Если тебе понадобилось положить значение в монаду, ты можешь с ним работать, используя все функции монад (и функторов, про них тоже почитай, и еще почитай про аппликативы, большинство монад так же аппликативы), включая в себя do-блоки. Но ты в любой момент можешь вытащить из таких монад значени(я), что в них леж(а)т. Но это справедливо не для всех монад. Есть монады IO, которые абстрагируют настоящие побочные эффекты. Вытащить из них значение невозможно безопасным образом, потому что функция перестанет быть идемпотентной! Но пока значение висит внутри монады, ее можно рассматривать как черную коробку, в которой хрен пойми что лежит. И если функция хочет работать с таким значением и как-то его доставить в возвращаемое значение, то эта часть возвращаемого значения должна стать тоже эдакой черной коробкой. И получится, что если закрыть глаза на все такие черные коробки и представлять, что нам пофиг на то, что в них лежит, то все такие функции останутся с грехом пополам идемпотентными. Конечно, они уже не будут чистыми, их нельзя будет так просто параллелизировать и лениво исполнять, но их можно будет все точно так же использовать в императивном контексте, например, do-нотации. Каждый do-блок теперь можно превратить в маленькую императивную программу, которая будет, например, делать какое-то интерактивное I/O. В зависимости от результатов этого I/O оно сможет вызвать какую-нибудь чистую функцию, но результат вычислений в этом блоке всегда будет лежать в IO монаде, и все, что его использует, должно будет так же "тейнтить" полученные от него по цепочке вызовов значения, и все такие функиции перестанут быть чистыми, но будут юзабельными во всяких do-блоках. И в конце концов все это докатывается до мейна, у которого тип... main :: IO ().
Вот так вот. По-моему, это гениально, и совершенно охуенно. Обожаю Хаскелль. Дай бог я нигде в этой стене текста не ошибся
Что до обилия IO, то при хорошем написании кода бизнес-логика будет вся чистой. При помощи всяких мэпов, байндов, лифтов и так далее можно легко использовать чистые функции в монадических вычислениях.
Вообще по-хорошему IO должно быть либо там, где есть какое-то прямое взаимодействие со страшным императивным миром за пределами программы, либо в какой-то функции, которая высчитывает что-то, использующее напрямую полученное из IO значение. При этом это значение может быть через fmap прогнано через вполне себе чистую функцию, которая все посчитает, но вернуть все надо будет в любом случае в монаде.
Это, кстати, еще и хороший способ разделить основную логику приложения от взаимодействия с окружающей средой, типа separation of concern. Второе будет в тэйнтнутых какой-нибудь IO-монадой функциях, доходящих по небольшой цепочке вызовов до мэйна, а первое - во всех чистых функциях, которые они вызывают.
не пойми превратно, PHP и язык 1C тоже считаю недоязыками программирования. хотя сам 1с-Программист и веб разработчик. Но проблем с С++ не наблюдаю.
Ну сумасшедший, что возьмешь!
сорок тыщ! сорок ёбаных тыщ строчек!
2) Количество строк зависит только от того как разработчики компилятора реализовали библиотеку
Так то оно все верно. You don't pay for what you don't use - плюсы именно за это и любят. Единственная проблема, это то, что иногда крупные проекты компилятся ну очень долго.
Интересный у тебя юзернейм на винде, а не тян ли ты случаем?
Долгая сборка это действительно проблема*. Но такова цена за типовую безопасность и низкий оверхэд шаблонов.
* - или нет?
В плюсах int main() и int main(void) одно и то же. Никакой разницы нету.
В С разница большая. Пустой список аргументов (без void) означает, что принимаемые аргументы не указаны и функция может принимать в качестве аргумента что угодно. Если стоит void, это означает, что функция не принимает никаких аргументов.
Детали тут
int main(void){ ... }
main(42);
я просто с js пришёл, там всякую хуйню творить можно
В плюсах будет ошибка при компиляции в любом случае.
Я в двух словах попытаюсь объяснить почему так.
В С и С++, каждые .c / .cpp файл (называется translation unit) компилится полностью независимо друг от друга. Поэтому если код какой-то функции присутсвует в одном файле (это назвается определение или definition), но использовать ее нужно в другом, то нужно предоставить т.н. объявление (declaration) функции. Когда компилится файл с определением функции, то в объектные файл добавляется код функции с ее именем (символом). Объявление функции позовляет ее использовать без наличие самого кода (определения). Обычно Declaration пишут в хедерах, и оно является просто указанием компилятору, что где-то есть такая функция с таким именем. Во время линковки это дело сшивается в одно целое и если какую-то функцию наяти не удалось, случается ошибка линковки.
Разница между С и С++ тут в том, что в С символ функции это просто ее имя. Т.е. линковщих не может никак проверить какие аргументы эта функция принимает. Следовательно и объявить функцию можно не зная какие аргументы она принимает, поэтому отсутствие аргументов означает, что неизвестно какие аргументы она принимает.
В С++, символ состоит не только из имени, но и из сигнатуры, поэтому перепутать две функции никак не получится. Это сделано чтобы можно было перегружать функции, при этом генерирую обычные С совместимые объектные файлы которые можно залинковать вместе. Символ функции формиркется из ее имени и сигнатуры особым образом который называется name mangling, поэтому при обявление нужно указывать какие аргументы она принимает всегда. Следовательно, обявление без аргументов это просто функция которая не принимает аргументов.