Pull to refresh

Comments 97

пожалуй лучший и самый содержательный гайд по Scala на хабре
Еще есть очень интересный язык от компании jetbrains — kotlinlang.org. Таже scala только проще в освоении.
Kotlin не совсем корректно сравнивать со Scala, скорее с Java/C#, и он их делает :)
ох, я бы Java с C# в один ряд не ставил)
Шарп делает Джаву? Я не в курсе просто :(
У нас один разработчик волею судеб был вынужден пересесть на год с C#/WPF на Java/Android. Рыдает и бьётся головой о стену. Говорит, что Java жутко убогая по сравнению с C#. Хоть enterprise-либы лучше.

Это чисто его мнение, а не моё! Я придерживаюсь нейтралитета и не верю, что там всё так плохо.
Это часто так бывает, когда человека вырывают из зоны комфорта.
За год можно было привыкнуть… Вчера опять был недоволен. Мол, generic-и в Java ненастоящие! И оператора typeof нет. Я, правда, не совсем уловил, что именно ему так не понравилось.
Generic-и стираются при компиляции, List во время выполнения это просто List
Вообще, в Java много «особенностей», к которым после более человечных языков привыкать не хочется
Когда пересаживают с нормального кресла на треногий табурет — возмущение естественно)
Зато трёхногий может стоять почти на любой поверхности ;)
Под JVM много стульев языков, дайте хотя-бы с колёсиками)
Вполне возможно, что есть еще сто интереснейших языков, но программистам платят не за интересность языка и не за легкость в его освоении, а за то, чтобы программа работу работала. Причем не дольше определенного времени и не потребляя больше определенных ресурсов компьютера. Поэтому Scala, как промышленно востребованный язык (то есть, специалисты по нему требуются во многие проекты), имеет громадное преимущество перед другими «интересными» языками.

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

Ну и напоследок, «конкурентные программы» — это ж надо так перевести! В-)
Я совершенно не понимаю аргумента:

«У этого языка код медленнее => Этот язык нельзя использовать в тех же целях».

Это чисто логическая ошибка, ибо из одного другое не следует. Допустим, при идеальных условиях код на Java будет быстрее кода на Scala. Тогда конечно лучше Java. Но идеального кода не бывает — подавляющее большинство систем написаны не самым оптимальным образом, и язык здесь второстепенен. Программы просто не используют все доступные ресурсы. Так какая же разница, будет ли код на Java не использовать эти ресурсы, или код на Scala? Скорость работы программ не может быть критерием выбора языка, пока не доказано, что она напрямую зависит от этого языка.
«У этого языка код медленнее => Этот язык нельзя использовать в тех же целях».

Покажите пальцем, где я такое сказал. Не покажете, потому что я не говорил. А сказал очень четко: «не дольше определенного времени».

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

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

Если бы было так, то для линейных алгоритмов мы бы до сих пор использовали код на ассемблере с хитрыми хаками, из-за которых алгоритм работал бы в n раз быстрее. Эти тесты слишком расплывчаты, и к ним обычно возникает очень много претензий. Конечно же алгоритм будет работать с разной скоростью, написанный разными людьми на разных языках в разных окружениях. И реализация может быть абсолютно разной. Производительность конкретного кода — необъективный параметр. Программа не будет состоять только из этого алгоритма, в ней есть еще много других компонентов, производительность которых никому не интересна. Но очень интересно, чтобы эти компоненты работали корректно, имели простой дизайн, быстро писались и легко поддерживались. Старые технологии уже не могут удовлетворить этим требованиям в полной мере — отсюда и движение в сторону ФП.

В конце концов, мультиязыковые проекты сейчас — вовсе не редкость. Если требуется, чтобы какой-то алгоритм работал быстро, и известно, что на языке А этого добиться проще всего — можно сделать интероп из другого языка в код на А, но остальные задачи решать наиболее пригодным способом.

И мне не понятно как вообще можно отрицать, что ваш абзац «В связи с этим, кстати...» может быть сведен к цепочке «У этого языка код медленнее => Этот язык нельзя использовать в тех же целях».
Тесты много чего покажут. И это часто очень существенный критерий для реальных проектов. В современном мире, именно в нем.

Код на ассемблере очень трудно писать и поддерживать, человекодень — тоже ресурс. Да и современные компиляторы (с С++, например) зачастую генерят более эффективный код.

Однако, никто не будет писать модель погоды на Python или Scala, как и не будет на них писать ядро ОС или систему торгов на бирже, или CAD, или 3D-игрушку, или фото/видеоредактор, базу данных, сервер сообщений и т.д. и т.п. Для всего есть своя область применения.
Соглашусь только про 3D игры. И то я бы взял в теперешнее время не С++, а что-нибудь из ряда Go, Rust.

А все остальное — запросто.

ejabberd — написан на Erlang.
erlyvideo — видеостриминговая система, Erlang. habrahabr.ru/post/114560/
backend в Twitter — написан на Scala. www.slideshare.net/al3x/the-how-and-why-of-scala-at-twitter
В AutoCad когда-то был встроен AutoLisp.
Есть кое-какие разработки ОС на Haskell: stackoverflow.com/questions/6638080/is-there-os-written-in-haskell

… Можно продолжать еще. Но зачем? Я уже в который раз наблюдаю, как люди с той стороны баррикад говорят, что если на языке X никто не пишет и не вздумает писать Y, значит это язык плох и ужасен. Очень часто под Y упоминают ваш список: 3D-игры, ядро/модули ОС, фоторедакторы… Фантазия, правда, этим и ограничивается. По-моему, пора бы уже понимать, что категорий софта десятки, если не сотни, и для большинства из них нет объективных причин использовать только мейнстримные языки. Например, я бы сейчас крепко задумался, если бы мне предложили писать MMO-игру на С++, а не на Erlang, просто потому что в С++ нет (нативно) этой замечательной концепции — модели акторов. Я боюсь себе представить, насколько сложный код получился в компании CCP…

И модель погоды я бы взялся писать не на С++, а на Haskell или Scala. Просто потому что мне бы хотелось иметь чистые функции, распараллеливаемые алгоритмы, кристально ясный код.
Уже потом я нашел тесты по производительности. Scala отстает всего на 25% от C++ (правда, памяти жрет в разы больше). Это очень хороший результат, я ожидал 5-10-кратного падения производительности. А при 25% можно писать почти все, что угодно, согласен.
Ах, да еще: High Freequency Trading на Haskell — это реально. Меня приглашали пособеседоваться в какую-то западную компанию, которая пишет HFT систему на этом языке.
Не уверен, что они пишут на Haskell нижний сетевой уровень, а верхний аналитический — почему нет? :)
Детали мне, к сожалению, не известны. По сочетанию HFT + Haskell гуглится много материала, но я не вчитывался, лениво.

Еще хотел бы упомянуть, что на Erlang весьма комфортно описывать протоколы нижних уровней, так как там есть удобная манипуляция данными на уровне битов (если я не ошибаюсь).
Однако, никто не будет писать модель погоды на… Scala, как и не будет на них писать систему торгов на бирже… базу данных, сервер сообщений и т.д. и т.п.

Scala с такими задачами отлично справляется. Например, ElasticSearch, OrientDB, Hadoop, Apache Spark тому доказательство. Да, они написаны на Java, но всё что написано на Java может быть написано и на Scala.
Уже согласился с большинством оппонентов, найдя и посмотрев тесты по сравнительной производительности (которых я и просил с самого начала, но которые никто так и не дал).
Однако…
Да, они написаны на Java, но всё что написано на Java может быть написано и на Scala.

— совершенно нелогичное утверждение, даже если вторая его часть и верна.
Ну вот хотя бы что-то:
togototo.wordpress.com/2013/08/23/benchmarks-round-two-parallel-go-rust-d-scala-and-nimrod/
Кстати, неплохая производительность.

Гугл тоже делал тесты в 2011, но что-то я не доваеряю их результатам (как разработчика Go):
readwrite.com/2011/06/06/cpp-go-java-scala-performance-benchmark
В большинстве программных продуктов большинство мест не являются узкими местами ни по скорости выполнения, ни по потребляемой памяти. Если же такие места будут выявлены, то их можно переписать на Java/C++/ASM. В современном мире гораздо важнее поддерживаемость и удобство (а, значит, и скорость с безошибочностью) разработки.
В большинстве программных продуктов большинство мест не являются узкими местами ни по скорости выполнения, ни по потребляемой памяти

Придерживаюсь обратного мнения, при опыте в 29 лет профессионального программирования.

В современном мире гораздо важнее поддерживаемость и удобство (а, значит, и скорость с безошибочностью) разработки.

Опять же, мой обширный реальный опыт говорит об обратном.
Нисколько не умаляя Вашего опыта хочу заметить, что 29 лет назад реалии разработки ПО были иными, и требования к программам были иными, сложность ПО тоже многократно выросла.
Вы говорите о том, что программа приемлема, если она работает не дольше определённого времени и потребляет не больше определённых ресурсов — по этим критериям Scala приемлема. Но ценность Scala в первую очередь не в этом, а в том, что она даёт программисту больше различных средств кода, повышая модульность и поддерживаемость (и, косвенно, отказоустойчивость). Я думаю, что не ошибусь, если скажу, что предыдущие комментаторы имели ввиду то, что эти свойства в современном мире важнее, чем экономия каждого байта, с чем я полностью согласен.
29 лет назад реалии разработки ПО были иными, и требования к программам были иными, сложность ПО тоже многократно выросла.

Да что ж вы все так упорно приписываете мне слова, которых я не говорил? Я не говорил, что 29 лет назад я работал программистом. Я начал им работать 29 лет назад, но работаю и сейчас, и прекрасно знаю современное состояние отрасли. Более того, первый проект, в который меня ввели 29 лет назад, имел полтора миллиона строк кода. Так что насчет сложности…
И опять, я нигде не сказал про экономию каждого байта. Зачем передергивать?
Сейчас уже в индустрии есть понимание, что нельзя хвастаться огромным количеством строк кода. Зато можно хвастаться малым количеством строк, которые делают то же самое.

Что-то вот такое я встречал в сети (интерпретация авторская, как в оригинале — не помню):

«Пришел к нему один ученик.
— Учитель! Я хочу достичь просветления!
— А сколько у тебя строк кода в том простом проекте, что я задавал?
— 100 000 строк, много комментариев, везде защитное программирование.
— Молод ты еще. Убери бессмысленные assert и комментарии — пусть код сам за себя говорит, тогда и возвращайся.
Вернулся позже к нему ученик:
— Учитель! Я убрал все лишние комментарии, заменил все assert и проверки на NULL на чистые функции, добавил юнит-тесты. У меня получилось 50 000 строк. Теперь-то я могу достичь просветления?
— Нет, ученик мой, все еще нет. Узнай про KISS и DRY, изучи библиотеки, отрефактори код и тогда уже возвращайся.
Вернулся позже к нему ученик:
— Учитель! Я отрефакторил код. Я убрал повторы, обобщил код, заменил велосипеды билиотечными аналогами. У меня получилось 10 000 строк! Теперь-то я могу достичь просветления?
— Да, теперь можешь. Вот посмотри, это мой код, который делает то же самое, что и твой. Здесь 500 строк.
И тогда ученик достиг просветления.»
Опять мимо. Я: 1) прекрасно знаю «понимание в индустрии» и 2) не хвастался, но лишь аргументированно оспорил утверждение, что 29 лет назад системы были «многократно проще».

Но самый главный аргумент против моего же мнения я нашел сам — сравнительные тесты производительности по разным языкам (см. выше). Scala там очень неплохо смотрится.
Ну и напоследок, «конкурентные программы» — это ж надо так перевести! В-)

Я считаю, что люди переводящие книги будут опытнее меня в переводах, вот отрывок из книги «Семь моделей конкуренции и параллелизма за семь недель»:
dmkpress.com/files/PDF/978-5-97060-244-7.pdf

Пример названия главы: «Конкурентные программы для конкурентного мира».

Что именно вас смутило в данном словосочетании?
В русском языке выражение «конкурентные программы» означает программы, конкурирующие между собой — не внутри себя, а между собой. То есть, когда программы конкурируют с другими программами.
И то, что какой-то переводчик перевел этот термин так неудачно, не значит, что надо его использовать.
Подскажите, пожалуйста, другой термин, чтобы я им пользовался.
Благодаря выступлению Роба Пайка, всегда, когда мне попадается слово «concurrency» в тексте, то сразу приходит на ум фраза «Concurrency is not parallelism». Термин же «многопоточные» на английском — multithreading. Получается, имеем два термина на английском: «concurrency» и «multithreading», но на русском они должны сливаться в один? Я считаю это неправильным.

В википедии фразу «Concurrency and data structures» переводят как «Одновременность и структуры данных». Всё же для меня слово «concurrency» по смыслу ближе к одновремменому или конкурентному, чем к многопоточному.
Лучше «concurrency» и «multithreading» будут сливаться в один термин (потому что технически они одно и то же и обозначают, только с разными акцентами), чем использовать по-русски неправильное выражение.
Подведу итог.

1) Программы, конкурирующие с другими программами, называются «конкурирующими программами», а не конкурентными (конкурирующий vs конкурентный).
2) Во многих источниках, связанных с техническим термином «concurrency», используется перевод «конкурентный» или «одновременный», а не «многопоточный».
3) Термин «многопоточный» на английском языке пишется как «multithreading», а не «concurrency».

Для себя делаю вывод, что выражение «конкурентные программы» правильное и ничего в нём «это ж надо так перевести» нет. Вы, со своей стороны, можете спокойно считать его неправильным. Засим считаю тему закрытой.
Что-то кроме наличия/отсутствия неизменного состояния я не увидел никаких гипотетических преимуществ Scala перед ruby. Опуская неясность с вопросом «чем же хорошо неизменное состояние» (идиот справится напакостить и вообще между одних констант), хотелось бы спросить автора (за неимением гербовой, может быть вы, как переводчик, растолкуете :), зачем тут вообще руби? Ну императивная Java автору надоела, это понятно. Scala для его задач круче — тоже ясно. Руби-то тут зачем?

Ну и, чтобы два раза не вставать: `strToInt` это же гораздо хуже отсутствия неизменного состояния. Что у нее с областью видимости? Один раз определил и теперь все имена пользователей, состоящие только из цифр, автоматом стали numeric? Не говоря о том, что `[1, '10'].map(&:to_i).min` в десять раз короче и в миллион раз понятнее.
Основное преимущество — статическая типизация, не нужно писать тесты на такие мелочи, как опечатки, и в целом увереннее себя чувствуешь, если скомпилировалось, значит, скорее всего, будет работать. Оно и в Java так, но в Java постоянно нужно обходить несовершенства системы типов, а здесь с этим попроще.
А неизменяемое состояние хорошо своей простотой — меньше сущностей при чтении кода, проще работать.
Статическая типизация сама по себе врядли кого-то волнует.

не нужно писать тесты на такие мелочи, как опечатки,

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

Грамотное применение типов может уменьшить число тестов в разы. Зачем мне делать assert(x.length=y.length), если у меня по системе типов в функцию передается список пар [(x,y)]?
Лично я за языки с опциональной типизацией типа Groovy, Julia или в какой-то степени Clay и шаблоны C++, а не за Haskell и Scala, потому что это позволяет сначала сделать динамический прототип, а потом отрефакторить, расставив типы, но это вопрос такой. Совсем без типов тяжко.
>а потом отрефакторить, расставив типы

«Нет ничего более постоянного чем временное» (с) кто-то умный
Это не так долго, если выставить типы у корневой функции, то они выведутся сверху вниз до самой нижней. Если возникнет пара неоднозначных мест, можно пофиксить. Но изначальный код пишется в динамике, и мне это нравится больше, чем хаскельный подход с «сначала полчаса думаем, какие у нас будут типы».
так зачем прототипировать без типов, когда можно сразу с типами?
Тогда приходится тратить время на редактирование «спецификации» типов, которая вполне может пожить и в голове. Редко когда с самого начала угадаешь с типами. Конечно, если не угадал, то и код нужно переписать, но только по месту использования, а не в двух местах.
А так 'Нет ничего более постоянного чем временное' тоже работает, если проще 100% покрыть тестами, проще покрыть тестами. В общем, такие языки позволяют использовать динамику, там где это удобно, и статику где удобно. Пишется полно всякого обслуживающего кода — отчеты там всякие, и тут можно один язык использовать. В случае С++ приходится тягать функции из питона через SWIG или заниматься прочей ерундой. На JVM полегче, но все равно один язык довольно больше удобство.
>>Тогда приходится тратить время на редактирование «спецификации» типов, которая вполне может пожить и в голове.

Каждому своё. По мне так языки с выведением типов в этом отношении не отличаются от динамических: если «не угадал с типами» переписывать приходится тоже только в одном месте
Из собственного опыта могу сказать, что в хаскелле ситема типов, обычно, не мешает. Как раз наоборот. И заставляет разрабатывать программу сверху-вниз. Т.е. сначала вы определяетесь чего вы хотите, какой тип у того, что вы хотите. Потом, вниз по цепочке вы определяете какие промежуточные типы вам нужны и так вплоть до тех типов что у вас есть на входе. Затем, пишите функции которые бы преобразовывали один типы в другие(соединяете стрелками, ага) и вуаля. Очень удобно прикидывать на бумажке или в каком-нибудь редакторе диаграмм (я люблю dia).
В том-то и дело, что система типов в хаскеле требует определенный стиль разработки — сначала семь раз отмерить, какие тебе типы нужны (ADT или кортежей достаточно? а тут у нас список или словарь нужен? или два словаря?), а потом отрезать код. А я предпочитаю скульптуры не из каменя высекать, а из пластилина лепить. Вылепил, а дальше прибил гвоздями типы с помощью аннотаций. В этом плане мне больше всего нравится язык Clay, в котором я даже поучаствовал немного, ныне застывший.
> из пластилина лепить
> язык Clay

Из глины, быть может? А чтобы Clay не застыл, его надо было водичкой смачивать.

По существу: реализованные типы — это половина решения задачи. На самом деле, больше думаешь, а не является ли предметная область чем-то большим, может это zipper или монада, или комонада? И если да, код упрощается в разы.
Если мы передаем два списка произвольной длинны, то в любом случае придется проверить их длинну.
А если список ровно из N элементов, то может быть в этом случае при статической типизации уберется ассерт, но добавятся аннотации.
Не вижу тут явного преимущества.

Грамотное применение типов может уменьшить число тестов в разы. Зачем мне делать assert(x.length=y.length), если у меня по системе типов в функцию передается список пар [(x,y)]?


Еще раз перечитал. Теперь понял о чем ты.
Но тут вовсе нет разницы, кто тебе мешает в языке с динамической типизацией передать список пар.
Так например работает конструктор dict в питоне — получает список пар (и не обязательно список а любой итерируемый объект). И что неужели тут случются какие-то проблемы?
Могу более жизненный пример дать, от Джоэля. Два типа unsafe_string, и safe_string, первый всегда получается от юзера, и может потенциально содержать XSS, инъекцию или что-то подобное, а safe_string — безопасная строка. safe_string неявно конвертится в unsafe_string, а unsafe_string в safe_string нет, только методом escape. Все функции, работающие с пользовательским вводом, возвращают unsafe_string. Все функции, кладующие что-то в базу или выводящие принимают safe_string. В итоге компилятор сам следит за тем, чтобы не было вредного кода в пользовательском коде, программист забыть не может.

И в принципе, как и в случае со списками, подобное можно написать и на динамическом языке, но есть один момент. Точнее два. Первый момент заключается в том, что человек без опыта статических языков вряд ли вообще о таком додумается — что строки могут иметь разные типы для помощи в проверках. Но это ерунда. _Принципиальная_ разница в том, когда упадет, если что-то написано не так. В статическом языке упадет при компиляции, в динамическом — во время теста (если повезет), или во время показа заказчику (если не повезет и ты как все забиваешь на тесты). И чем мощнее система типов, тем больший процент ошибок можно перенести на время компиляции. В Java, например, из-за ее фатальных недостатков, многие вещи проще делать через даункасты из Object — это та же динамическая типизация по сути. Все эти NullPointerException, ClassCastException — это вовсе не обязательно, чтобы в рантайме падало.

Вот чтиво про тесты в статических языках:
spin.atomicobject.com/2014/12/09/typed-language-tdd-part1/
spin.atomicobject.com/2014/12/10/typed-language-tdd-part2/
Про unsafe_string тут опять не понятно, при чем тут типизация.

Вот смотри если ты не используешь TDD то программа у тебя упадет в любом случае, и тут никакая статическая типизация не поможет. А если используешь то очепятка или забытый импорт отловится на этапе запуска тестов.
Кроме того, чтобы допустить очепятку нужно неплохо постараться, быть упертым и уверенно идти к этой цели — игнорировать автодополнение и игнорировать варинги среды разработки.
Да я много слышал подобных рассуждений, от людей которые проповедуют статическую типизацию. На деле таких ошибок почти никогда не происходит. Зато я постаянно вижу стэктрэйсы от всяких API на Яве, в том числе в досаточно серьзеных проектах. Почему-то не спасает их статическая типизация.

>Про unsafe_string тут опять не понятно, при чем тут типизация
При том, что в статике тебе не нужно тестов, чтобы проверять эти случаи. Вообще. Если забыл где-то — оно не скомпилируется. И так как это бесплатно (что в плане производительности, что в плане затрат времени), этим можно пользоваться. Потратил время, а потом забыл.

>Вот смотри если ты не используешь TDD то программа у тебя упадет в любом случае, и тут никакая статическая типизация не поможет
Да нет, поможет. Хардкорное TDD вообще редко используют в статических языках, потому что не нужно. Тесты пишут уже после кода. Дилемма простая, в статике ты описываешь типы и пишешь мало тестов, а в динамике ты пишешь много тестов, очень много тестов, нужно больше тестов. И в чем профит, в экономии времени? Так в динамике время реально экономится, когда тестов не пишешь вообще :) А если их писать, то времени приходится тратить больше, чем на типы… Это хорошо видно по распределению проектов — динамика в основном используется как CRUD примочка к базе, которой упасть в принципе не страшно, для скриптов автоматизации, для прототипов и расчетов… А статика — когда куча умных перцев готовит проект на годы. И первоначальные затраты времени окупаются сторицей. Я ничего не проповедую, говорю как есть просто. У меня специфика такая, что я за динамическими языками провожу больше времени, мне холиварить вообще не о чем.
>На деле таких ошибок почти никогда не происходит.
Ну это легко проверить, посмотрев на багтрек любого проекта.
>Зато я постаянно вижу стэктрэйсы от всяких API на Яве, в том числе в досаточно серьзеных проектах.
Я написал выше, ява очень часто вынуждает динамически кастить типы, этот язык не совсем показатель.
>Почему-то не спасает их статическая типизация.
Но это и не панацея, но вопрос же не стоит «зачем мучиться со статикой, когда есть такая хорошая динамика». Патчить зрелый статический проект, в котором все типы давно написаны, намного приятнее, чем ковыряться в динамическом проекте в 10 раз меньше. Писать с нуля проще и быстрее скриптами…
Да нет, поможет. Хардкорное TDD вообще редко используют в статических языках, потому что не нужно. Тесты пишут уже после кода. Дилемма простая, в статике ты описываешь типы и пишешь мало тестов, а в динамике ты пишешь много тестов, очень много тестов, нужно больше тестов. И в чем профит, в экономии времени? Так в динамике время реально экономится, когда тестов не пишешь вообще :) А если их писать, то времени приходится тратить больше, чем на типы… Это хорошо видно по распределению проектов — динамика в основном используется как CRUD примочка к базе, которой упасть в принципе не страшно, для скриптов автоматизации, для прототипов и расчетов… А статика — когда куча умных перцев готовит проект на годы. И первоначальные затраты времени окупаются сторицей. Я ничего не проповедую, говорю как есть просто. У меня специфика такая, что я за динамическими языками провожу больше времени, мне холиварить вообще не о чем.


Кажется мы тут уже ушли в другую тему «Писать тесты или не писать».
TDD (здесь я имею ввиду не именно TDD, а любые методики написания тестов) не используют в двух случаях, первый случай — это когда не умеют писать тесты, а второй случай когда затраты на тесты не окупятся, т.к. это какой-то одноразовый не критичный код.
У меня в проектах полно тестов, но там нет каких-то специфических тестов связанных с типизацией.
Вот выше в статье например пример с вычислением чисел фибоначи. Чтобы определить, что эта функция работает, статическая типизация никак не поможет. Мы напишем функцию которая будет всегда возвращять ноль и она спокойно скомпилируется Чтобы убедится что функция работает, нужны юнит тесты. А они нам заодно и будут гарантией от очепяток и забытых импортов, в случае динамического языка. Но тут нет никакой разницы можду статическим и динамическим, набор тестов будет один и тот же.
В чем экономия времени. Очень просто.
Вот мы написали тест и функцию. А потом нам понадобилось изменить реализацию, например сделать рефакторинг или оптимизировать по скорости или выпились из кода устаревушю библиотеку. Если тестов нет, то придется заного проходить весь цикл тестирования, а если тесты есть, то этого не требуется.


Можно подумать, от TDD она перестанет падать.
Зато я постаянно вижу стэктрэйсы от всяких API на Яве, в том числе в досаточно серьзеных проектах. Почему-то не спасает их статическая типизация.

Так выше уже написали, что статика статике рознь, и много где можно наткнуться на динамические рудименты.
Попытку вызвать метод, не определенный на данном типе, не заметить мгновенно в руби очень трудно. Даже если специально писать код вслепую. «если скомпилировалось, значит, скорее всего, будет работать» — ой, я абсолютно не согласен. Будет запускаться — да. Алгоритмические ошибки обычно связаны не с тем, что с типом напутали (по моему опыту).

Ну а «неизменяемое состояние хорошо своей простотой» — это какая-то мантра, а не аргумент. Что в неизменяемом состоянии простого? Особенно в chain, как в авторских примерах?

Всмысле «не заметить очень трудно»? Упадет в рантайме и привет. А опечатки возникают при мерже в git, например — это не всегда перед глазами. Приходится писать тесты на то, на что в статическом языке тестов не стал бы писать, потому что и так все работает.

В неизменяемом состоянии просто то, что если конструктор правильный, то состояние сущности всегда правильное. То есть конструктор и методы можно оттестировать отдельно, а в случае изменяемого состояния результат теста может зависеть от порядка вызова методов — что, естественно, никто в жизни тестами не покроет. Читать код удобно тоже — функции превращаются в трубы, которые преобразуют сущности.
Вот в этом именно смысле. Какая разница, упадет в рантайме, или при компиляции? Еще раз повторяю: если падает (или отлавливается компилятором) — это не ошибка, это описка. Которую одинаково легко поймать вне зависимости от языка (ну, кроме ассемблера и plain c).

Ох, мама дорогая. А с изменяемым состоянием трубу не написать, что ли? Если сеттеров, явных и неявных, у объекта нет, то будь он триста раз изменяемый, ничего от порядка вызова не зависит. В оригинальном тексте автор боится, что между map и reduce какая-то злая инопланетная тварь ему коллекцию испоганит. Это надуманная ерунда.

Короче, мы тут выучили умные слова, смысл не разумеем, но повторяем и радуемся. Ни одного _аргумента_ я так и не услышал. Вон мне там даже внизу написали, что «смысл в том, чтобы показать преимущества функционального подхода перед императивным». Ну так возьмите эрланг, у него-то преимуществ полно́ (и есть продакш.версия, в отличие от, например, хаскеля). Нет, возьмем скалу и высосем из пальца кучу преимуществ.

На простом php можно запросто писать используя только функциональный подход. И на джаве можно (придется поиграть в шахматы с коллекциями и рефлекшеном). И на шелле можно. Hadoop en.wikipedia.org/wiki/Apache_Hadoop, например, классическая имплементация мап-редьюса на (опа) джаве.
и есть продакш.версия, в отличие от, например, хаскеля

На сколько хорошо вы разбираетесь в данной теме?
Я дискуссии в стиле ad hominem не веду, уж извините.

P.S. «Насколько» тут пишется слитно, если это не вопрос про мою зарплату, конечно.

Мне не интересна ваша зарплата, мне было интересно на чём вы основываете данное утверждение, на собственном опыте или вам бабка во дворе сказала.
>>Какая разница, упадет в рантайме, или при компиляции?

O_o вы это серьёзно?
>Какая разница, упадет в рантайме, или при компиляции?
Огромная. При компиляции оно упадет при мне, а когда падает в рантайме — ну, если повезет, выловит тест, но раз в год и палка стреляет, а реальные люди почему-то отличаются от отличников из книжек по TDD, особенно когда сдача проекта вчера.

>А с изменяемым состоянием трубу не написать, что ли?
Я пишу «Читать код удобно», а вы мне что? Можно зделоть? Не понятно, о чем разговор, любовь к неизменяемости вообще с функциональностью слабо связана. const везде писать и в C++ рекомендуют, и у Макконнелла что-то подобное есть.

>В оригинальном тексте автор боится, что между map и reduce какая-то злая инопланетная тварь ему коллекцию испоганит. Это надуманная ерунда.
В оригинальном тексте много надуманной ерунды, да. Но это больше из-за вводного формата статьи. Сейчас из функциональщины взято все, что может быть легко перенесено в императивные языки, и поэтому особо такие статьи не впечатляют. Ну лямбды, ну вывод типов, а у нас вон linq и var есть. А на Rust если посмотреть, там и тайпклассы, и паттерн матчинг. Теперь впечатлять могут только вещи, которые уже так просто в императивный язык не перенесешь, потому что там все завязано на особенности этих языков. Типа vector fusion в хаскеле. А Scala лучше Java прежде всего как императивный язык, многие ее хотя бы из-за этого выбирают.

>На простом php можно запросто писать используя только функциональный подход.
Совсем унылые аргументы языкосрача пошли. Ну делойте, раз можно зделоть, вас кто-то насильно скалкой кормит что ли.
Я с самого начала говорил то же самое, что сейчас говорите вы. Я же статьей неудовлетворен, а не скалой.

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

А, ну и про рантайм. Не знаю, как вы, а я ни разу не сталкивался с проблемой «все сломалось из-за ошибочного типа». Обычно все ломается из-за того, на что тест толком не написать. И императивный тут язык, функциональный ли, разница невелика.
>Забавно, вы в предпоследней реплике, например, пишете чуть не дословно то, что в последней реплике обзываете «языкосрачем».
Я не против языкосрача, я против унылых аргументов. Когда идет аргумент, что на php можно сделать, ну да — вот github.com/ircmaxell/monad-php, но кто в здравом уме будет это использовать.

use MonadPHP\Identity;
$monad = new Identity(1);
$monad->bind(function($value) {
return 2 * $value;
})->bind(function($value) {
var_dump($value);
});

Функциональное программирование, это же не просто комбинаторы комбинировать а-ля linq to objects, как во времена SICP, в функциональной среде постоянно рождается что-то новое, что переходит в мейнстрим, сейчас это куча дополнительных фич и принципиально другой способ кодирования, который на императивных языках выльется в кашу из лямбд и тернарных if'ов вместо паттернматчинга.

>Не знаю, как вы, а я ни разу не сталкивался с проблемой «все сломалось из-за ошибочного типа».
А это не всегда видно, что типы могут помочь. Например, от всего пласта XSS ошибок и sql-инъекций в статическом коде можно избежать парой классов, но если рассуждать, что все строки одинаково полезны — уже не получится. От пласта ошибок единиц измерения, от которых ракеты падают, между прочим, тоже можно типами.
Но здесь дилемма статика/динамика непринципиальна (любые статические типы можно проверять и в динамике, и падать в рантайме), а вот сам факт падения при компиляции штука очень нужная и полезная.
Один раз определил и теперь все имена пользователей, состоящие только из цифр, автоматом стали numeric?

На самом деле нет.
Будет производиться дополнительная проверка, число мы получили или нет, и если нет, существует ли способ привести полученное к числу.
Суть данной статьи не в том, чтобы показать преимущества Scala перед другим языком программирования, а в том, чтобы показать преимущества функционального подхода перед императивным. В примерах Scala можно с лёгкостью заменить на Haskell и получить тот же (возможно даже и лучший) результат. И если вас действительно заинтересовало функциональное программирование, то как-раз советую присмотреться к Haskell (а потом вернуться к Scala и понять насколько этот ЯП крут :).
UFO just landed and posted this here
Будучи программистом на Ruby, строгая типизация в Scala ощущалась в начале как бремя…

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

Неверно. В Scala, так же как и в Java, точкой входа является статический метод main (скорее всего это ограничение jvm). Мы либо явно его определяем, либо наследуем трейт App. Если речь идёт о repl, то там код выполняется в теле неявно созданного App. Так что от main никуда не деться.
Да, имелось в виду, что этот код можно запустить в REPL. Просто тем, кто не знаком со Scala может показаться что в этом коде так же пропущены геттеры, сеттеры и конструктор, как в примере с Java.

И если совсем уж заморочиться, то можно обойтись и без main с App:

#!/usr/bin/env bash
exec scala "$0" "$@"
!#

println("Hello!")
В Scala for-генератор – это синтаксический сахар для функциональной композиции.

Э… Что, простите?

for — синтаксический сахар для filter/flatMap/map, но никак не функциональной композиции.
Основывал своё высказывание по доке:
http://docs.scala-lang.org/tutorials/FAQ/yield.html

«Scala’s “for comprehensions” are equivalent to Haskell’s “do” notation, and it is nothing more than a syntactic sugar for composition of multiple monadic operations.»

«composition of multiple monadic operations» — композиции нескольких монадических операций. Это никак не функциональная композиция, да и не композиция вовсе на самом деле — просто-напросто, слегка завуалированный fluent interface
Вполне себе композиция функций. x.f().g() === g'(f'(x)) === (g'. f') x
В вашем тождестве эквивалентен результат, но не способы его получения.
И написать val mapFilter = map(_+1) . filter(_ > 0) в Scala не получится — map/filter, это не полиморфные функции, а методы класса.
Никакой композиции нет во fluent-интерфейсе, а есть лишь последовательность вызовов.
Вы правы, с композицией функций я погорячился.
g(f(x)) это не композиция функций а вызов. Композиция была бы

g. f где результатом была бы функция
Cтоит отметить, что при объявлении функции не обязательно было указывать тип возвращаемого значения, компилятор Scala выведет его сам.

Для рекурсивных функций обязательно.
Код Scala компилируется в байт-код для JVM. Можно ли взять программу на Scala и переписать ее на Java так, чтобы на выходе был практически идентичный байт-код?
Интересно, как устроены хитрые функциональные штуки и как можно их реализовать в чистой Java.
В принципе, если посмотреть исходники, там нет ничего невозможно сложного или радикально необычного. Многие Scala-specific вещи (например, с типами) не спускаются на уровень JVM, другие имитируются с помощью стандартный JVM-механизмов (например, lazy-значения сделаны через double-checked locking с битовым полем, а объекты-компаньоны — через статические классы с постификсом .MODULE$)
Иногда можно, но scala-library окажется в зависимостях (а довольно много магии в ней). Некоторые вещи из скалы нельзя будет напрямую реализовать на яве.
UFO just landed and posted this here
Sign up to leave a comment.

Articles