Как стать автором
Обновить

Комментарии 126

Всегда задавался вопросом: как люди умудряются так быстро изучить столько языков, чтобы выносить о них столь ёмкие суждения? Тут на изучение Java на уровне читателя уходит три года, и всё равно пробелы остаются. А люди за год по 10 языков изучают… Или это я у мамы особенный?
Рискну предположить, что после 3-4 изученного языка остальные учатся очень легко, буквально за неделю. Ведь концепции в языках одни и те же, просто синтаксически выражаются по-разному. Тут как с иностранными языками.
А разве изучение языка заканчивается на синтаксисе? Э-э-э-э, не, брат, после изучения синтаксиса изучение языка только начинается.
Во-первых, концепции это вовсе не синтаксис. И во-вторых, теже монады, скажем, по идеологии весьма похожи, везде где они есть, и отличаются в основном только синтаксисом. Потому что в основе по сути — одинаковая математика. И еще можно назвать кучку подобных концепций, типа регулярных выражений, например — один раз изучил, и больше нигде проблем не испытываешь.
sshikov,Insferatu, с одной стороны, я вас понимаю и не спорю с этим. Вопрос не в конструкциях, а в, если позволите, закидонах компилятора\интерпретатора. Монады, иерархии, исключения, лямбды, коллекции и функторы — оно всё хорошо и просто на демонстрационных проектах. Но ведь изучение языка и на этом не заканчивается.
Самое интересное начинается, когда знакомишься с закидонами отдельных языков, когда начинаешь видеть прыщи на напудренном личике компиляторов. Когда на Си начинаешь использовать callback, на плюсах — колдовать compile-time шаблоны, в шарпах синхронизировать потоки, изменять java-класс на лету не перезапуская приложения, оборачивешь в haskell'е подтекающий поток и пытаешься разобраться, какой из случайно подключенных файлов-библиотек заменяет твой метод в Ruby.
Конечно изучение на синтаксисе не заканчивается. Но ведь и не обязательно с него начинается!

То что вы описываете — это уже тонкости. Далеко не каждый с ними вообще столкнется. Можно спокойно программировать много лет, ничего про это не зная. Вы не будете экспертом — но вы не будете при этом и начинающим.
> закидонах компилятора\интерпретатора

Тогда это называется изучением компилятора (или платформы), но не изучением языка. Язык — штука идеализированная. И понять чего она стоит действительно не сложно. Иногда мне кажется, что можно ввести чеклист на две сотни опций, заполнив который, можно выяснить всё что нужно о функциях языка.
Есть и такое. А есть пробелы в спецификации, в которых код может вести себя не так, как кажется. Например, у плюсов есть неопределённое поведение, которое, по хорошему, должно быть ошибкой, но не вызывает падение приложения, так как его отлов дороже. Кроме них есть ещё платформозависимое и аппаратнозависимое поведение.

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

Если ограничиться только синтаксисом и концепциями верхнего уровня, можно получить неверное общее мнение о языке. Одно время хабровчане фанатели от рубинов, сейчас эта любовь плавно перетекла к Go и Scala. Хотя и тот, и другой имеют очень много изъянов, прежде всего по ту сторону монитора. Последний, к примеру, не очень расторопен при компиляции, что для привыкшего к тестам дебагом программиста не очень приятно.
Я имел в виду не только синтаксис. Ведь в ядре разных языков (в их компиляторах или интерпретаторах) могут использоваться весьма схожие принципы. И если ты подробно изучал один язык раньше, то изучая новый ты заметишь всё те же знакомые принципы, и тратить времени на их понимание и изучение не придётся. Взять к примеру популярные Java и C#. Если человек с нуля учит Java, ему предстоит изучить что такое виртуальная машина, что такое JIT-компилятор, что такое сборщик мусора, и т.д. и т.п. А если вторым языком он начнёт учить C#, то он с удивлением обнаружит, что некоторые из этих концепции присутствуют и в нём. И достаточно лишь обратить внимание на различия между реализациями этих концепций. Вот и тратится на изучение гораздо меньше времени.
НЛО прилетело и опубликовало эту надпись здесь
>Язык программирования Scala является «симбиозом» Java и C#

Где вы откопали это утверждение? Авторы Scala разрабатывали новые языки (Pizza, GJ) задолго до появления c#, скажем так, примерно лет за пять. И в истории появления языка C# кажется не упоминается вовсе. Можно цитатку?
Тоже резануло. Насколько я понимаю, он тогда уж на F# похож. Да и это еще вопрос кто был первым Scala, F# или современный C#.
Я про это и толкую, кто первым — далеко не факт. Согласно википедии, c# появился в 2000. При этом с 1990 существовал скажем Haskell, который очевидно значительно большее влияние оказал на формирование идеологии Scala.

При этом заметьте, что сегодняшний и тогдашний c# — это две большие разницы. В тогдашнем не было почти ничего такого, что могло бы вдохновить на создание нового языка на платформе JVM, тем более людей, которые в 2001 уже создали компилятор Pizza, где уже были явные намеки на ФП (функции как сущности первого класса, например).

А проект этого языка, как и GJ (прототип generics) и подавно появились где-то в 1998, когда c# просто не было. Не мог он вдохновить никого, просто по времени не выходит.
Насколько я понимаю, он тогда уж на F# похож.

В Scala довольно сильно похожа на OCaml. Конечно, отличий в синтаксисе довольно много, но идеологическое наследие довольно легко проследить. К примеру, систему модулей из ML в Scala смогли унифицировать с объектной системой: вместо module type теперь обычный интерфейс (trait), вместо module — object, вместо функторов — наследование.


Хм, даже нашлась довольно интересная презентация на эту тему: http://lambdafoo.com/scala-syd-2015-modules/


F# так вообще по сути OCaml на .NET и без функторов.

3 года на уровне читателя что-то и правда многовато.

Ну я же только читаю…

Из индусов за это время делают писателей. Правда читатели из них так-себе :)

Писателем можно стать за две недели, ума особого тут иметь не надо.
Это первый язык 3 года… потому что вы учите не язык, а паттерны, общий фундамент. Я 5 лет изучал C++, прежде чем осознал, что неплохо в нем ориентируюсь. Но после, каждый следующий язык был таким же как C++, только с другими подходами, я просто понимал что это тоже самое, только по другому. Достаточно было 2-ух недель, чтобы понять что Java — это jvm байт код, что у него есть по синтаксису, что по стандартной библиотеке. Что lua или js — это уже в основном jit компиляция и возможность переиспользовать код в runtime, с соответственными потерями в производительности, что доступы к переменным в этих языках — это обращения к хеш массивам по строковым ключам. Я это понимал, потому что в принципе все это можно было бы сделать и на C++, но это было выражено в виде дополнительного синтаксиса, компилятора и новой стандартной библиотеки.
Нет-нет, пишу я на плюсах, и тут у меня нет проблем. Java и C#, конечно, близки, но очень часто именно привычка CPP мышления заставляет плодить на них говнокод. Причём, говнокод работающий и даже работающий неплохо.

Переход в другие парадигмы «на 5 минуток» точно так же не даёт эффекта. Да, я выучил, с чем едят монады и как делать функторы. Но я ещё не распробовал их вкус, на каких задачах я буду с удовольствием разжёвывать лямбды, а на каких я опорожню желудок и потребую обратно мои богомерзкие плюсы, потому что не могу контролировать накладные расходы этапа выполнения.
Есть люди, у которых нету личной жизни, которые способны уделить время учебе, саморазвитию и работе по 10-12 часов в сутки. В универе без проблем можно попробовать 4 языка программирования сдавая лабораторные работы. На практике уже придется прыгать между вакансиями. А в свободное от работы время поработать над собственным проектом.
«И я там был, на пары ходил, по ушам текло, в зачётку не попадало»©
А есть еще просто талантливые люди.
Ну я устроился Scala-разработчиком не зная Java. Мне это не особо мешает, тем более что sbt проще в использовании, чем Maven.
Так как Scala-разработчиков сложно искать, у нас начали брать Java-разработчиков и переучивать. Пока это проблем не вызывало. Scala они осваивают очень быстро, сложность языка преувеличена.
сложность языка преувеличена

Спорное утверждение. Сильно зависит от того, как на нём писать. Если на нём пишут недавно переученные Java-программисты, то, наверное, код принципиально не сильно отличается от аналогичного Java-кода и потому выглядит простым.
На мой взгляд, это один из самых сложных языков. Он мне показался сложным даже после повторного прочтения Programming Scala во времена Scala 2.8, и с тех пор ещё много всего добавилось (макросы, к примеру). Система типов слишком тяжеловесная (generic classes, abstract types, existential types, compound types, path-dependent types, dear god please make it stop).
Помню, пытался реализовать свой Option[T] для разминки. Казалось бы, должно быть просто, но в итоге убил кучу времени и всё равно получал ошибки компиляции, которые было сложно расшифровать. К примеру, написать аналогичный Maybe a в Haskell — дело десяти минут, даже если не использовал язык долгое время. Cake-pattern тоже тяжело даётся, даже после опыта с compile-time dependency injection через функторы в OCaml.

dear-god-please-make-it-stop types — это исключения для экстренного выхода из приложения?

Это отсылка к слайду в презентации Роба Пайка "Another Go at Language Design"


public static <I, O> ListenableFuture<O> chain(ListenableFuture<I> input, Function<? super I, ? extends ListenableFuture<? extends O>> function) dear god make it stop

a recently observed chat status

http://web.stanford.edu/class/ee380/Abstracts/100428-pike-stanford.pdf

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

Написать хорошую библиотеку в принципе сложно, независимо от языка. Моё утверждение в другом: даже простые задачи в Scala существенно труднее, чем они должны быть, из-за сложности языка. Понятно, что энтерпрайз в основном заключается в перекладывания данных из одного XML в другой и валидаций, и бОльшая часть кода относительно простая, но когда требуется сделать что-то нетривиальное, я обычно думаю "как бы я абстрагировал это в Haskell?", получаю тривиальное решение, а потом пытаюсь смоделировать его в Scala.
Вот все говорят про "тайп-классы на имплиситах", а мне вот тайп-классы нравятся гораздо больше. Синтаксически гораздо легче, и не нужно помнить замысловатые правила поиска неявных объектов в разных скопах.


В OCaml, кстати, тоже имплиситы завезти хотят Modular Implicits

Не нужны тайп классы и имплиситы для промышленной разработки. Разве что для тестов — чтобы красивый DSL сделать.

имплиситы для промышленной разработки

Да ладно, каждый первый первым делом объявляет всякие коннекторы к базе и тред-пулы имплиситами.

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

для протаскивания существует dependency injection. Скаловский подход с cake pattern, синглтонами и имплиситами ошибочен.

Я бы не был так категоричен. Для кого-то это вполне удобный подход, но лично мне он тоже не очень нравится, возможно я так и не проникся духом scala за то время, что пишу на ней.
НЛО прилетело и опубликовало эту надпись здесь
А вы хоть раз писали на cake pattern'e? Особенно, когда зависимостей > 2?
НЛО прилетело и опубликовало эту надпись здесь

А также
5) много дополнительного кода
6) сложно конфигурировать в рантайме, т.к все зависимости прописаны в коде
7) самое важное — сложно тестировать, т.к. запуск модуля с парой моков вместо реальных классов сделать очень непросто. Также подход с синглтонами усложняет параллельное тестирование


По моему опыту, самый оптимальный DI для больших проектов на скале — это Guice.


Вообще печально наблюдать, как академическое scala-сообщество наступает на уже отполированные Java/C++ программистами грабли. Что синглтоны — это плохо, что перегрузка операторов превращает программу в нечитабельное мессиво...

НЛО прилетело и опубликовало эту надпись здесь
НЛО прилетело и опубликовало эту надпись здесь
НЛО прилетело и опубликовало эту надпись здесь
Не правда про Guice. Scaldi хорош

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

Так абстракции в любом случае скрывают конекшены и тредпулы от пользователей и зданий, причем тут имплиситы? А большинство потребностей в опосредованности связей для меня решает DI.

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

Ну вот видите, на мой комментарий ответили два разработчика, один считает подход очень удачным, другой — очень неудачным. Теперь найдите Haskell-программиста, который считает typeclasses плохой идеей.

Так хаскель, я надеюсь, не претендует на роль промышленного языка? Или на простоту?

Или на простоту?

А почему нет? Хаскель — это довольно простой и логичный язык. Я считаю его языком на порядок более простым, чем OCaml и, тем более, Scala. Там не нужно помнить множество правил, синтаксических конструкций, компот из разных систем типизаций и неявных объявлений, чтобы понимать, как компилятор будет интерпретировать твою программу.


Вся "сложность" Haskell в том, что думать по-другому и разбираться в абстракциях, чтобы использовать язык и библиотеки эффективно.


на роль промышленного языка?

Пожалуй, основная деталь, которая мешает Хаскеллу в проде — это вездесущая ленивость по-умолчанию. Она существенно затрудняет анализ производительности и при неумелом использовании ведёт к так называемым space leaks, которые могут выстрелить в самый неподходящий момент.
Эта одна из причин, по которой разработчики из Standard Chartered (которые владеют более чем миллионом строк кода на хаскеле), написали собственный компилятор Mu, который по-умолчанию использует энергичные вычисления.

НЛО прилетело и опубликовало эту надпись здесь
НЛО прилетело и опубликовало эту надпись здесь
какая-нибудь инфа кроме этого видео?

Честно, говоря, про него мало что известно, исходников нет. Я сам узнал о существовании Mu относительно недавно из презентации Дона Стюарта на Google Tech Talk Haskell in the Large.


Пару деталей можно найти в блоге Дона:


Yes, we use Mu, which is our Haskell compiler. It’s source compatible with GHC, but with strictness on by default.

Кстати, в GHC начиная с версии 8.0 есть прагма Strict с аналогичным эффектом.

НЛО прилетело и опубликовало эту надпись здесь
Не надо путать два понятия.
Имплиситы используются далеко не только для реализации классов типов. И сложности возникают именно с другими вариантами применения.
Сам я имплиситов немного побаиваюсь, но их использование в библиотеках часто делает использование этих библиотек гораздо удобнее.
Я не гнушаюсь использовать имплиситы для передачи типа дженерика, но только потому что неявность здесь минимальная, а это временами очень удобно. Но подход этот всё равно довольно сложен для понимания в деталях. В котлине вот придумали намного более простой способ решить эту проблему (информация о типе в inline-функции) и хотя применение этой фичи ограничено, простота делает его использование очень приятной.
Я как раз утверждаю, что простые и средние задачи на Scala решать существенно проще, чем на большенстве других языков.
Конечно, зависит от задачи. Очень многое на Haskell делается красиво и тривиально. Но когда начинается ввод/вывод и обработка ошибок Haskell почти ни чего не дает, по сравнению с распространенными языками.
Но когда начинается ввод/вывод и обработка ошибок Haskell почти ни чего не дает

Вот тут я не совсем понял. Что именно "не даёт" Haskell? Чего-то не хватает в стандартной библиотеке?
Библиотек для эффективного потокового ввода-вывода больше, чем должно быть, потому что приходится выбирать, какую из них использовать (извечный вопрос "Pipes или Conduits?").
Для обработки ошибок есть Either, который весьма удобно использовать вместе с MonadError. Исключения тоже есть, но они считаются bad practice и не такие удобные, как в той же java.

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

Ох, опять. Чтобы добавить корректную обработку ошибок в "готовый" код (т.е., видимо, в код, в котором её нет), нужно всё равно всё переписать, независимо от языка. Исключения не являются универсальным решением проблемы, скорее создают только больше проблем.


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

Вообще говоря, это очень спорные утверждения. Роль ленивый вычислений в обработке ошибок принципиальна. Именно благодаря ленивым вычислениям можно писать красивый монадический код с обработкой ошибок, в котором в каждой строчке не стоит if err != nil.


Смеха ради набросал небольшой примерчик, чтобы продемонстрировать идею и не быть голословным. Иногда всё работает успешно, в 10% случаев возвращается ошибка с описанием. Расширения языка используются в основном для небольшого сокращения бойлерплейта.


{-# LANGUAGE FlexibleContexts, ExistentialQuantification, Rank2Types #-}
import Control.Monad.Except
import System.Random (randomRIO)
import System.Environment (getArgs)
import System.Exit (exitFailure)
import System.IO (hPutStrLn, stderr)

type Person = String

data FbError
  = NetworkError String
  | ApiError String
  | InvalidAccount Person
  deriving (Eq, Show)

type FbDownloader = ExceptT FbError IO
type FbFun a b = forall m . (MonadError FbError m, MonadIO m) => a -> m b

fbDb :: [(Person, [Person])]
fbDb = [ ("alice", ["bob"])
       , ("bob",   ["alice", "eve"])
       , ("eve",   ["bob"])
       ]

getFriendsOf :: FbFun Person [Person]
getFriendsOf person = do
   x <- liftIO $ randomRIO (1 :: Int, 100)
   case x of
     _ | x < 6  -> throwError (NetworkError $ "Failed to download friends of " ++ person)
     _ | x < 11 -> throwError (ApiError "Your api key is invalid :[")
     _ | otherwise -> do
           liftIO $ hPutStrLn stderr ("Requesting friends of " ++ person ++ " ..." )
           case lookup person fbDb of
             Nothing -> throwError $ InvalidAccount person
             Just ps -> return ps

getFriendsOfAll :: FbFun [Person] [Person]
getFriendsOfAll = fmap concat . mapM getFriendsOf

getFriendsOfFriends :: FbFun [Person] [Person]
getFriendsOfFriends people = getFriendsOfAll people >>= getFriendsOfAll

runDownloader :: FbDownloader a -> IO (Either FbError a)
runDownloader = runExceptT

main :: IO ()
main = do
  names <- getArgs
  result <- runDownloader $ getFriendsOfFriends names
  case result of
    Left  e -> hPutStrLn stderr (show e) >> exitFailure
    Right l -> mapM_ putStrLn l
Тогда такой вопрос. Вы пишите быстрый, компактный и эффективный код? Вы можете добавить новую функциональность написав всего 2-3 строчки? Вы используете всю мощь языка и стандартной библиотеки? Или пишете код уровня «паскаль, 10 класс школы»? Вы умещаете 1000 строк класс из Java в 100 строк Scala?
Мы пишем код, который удовлетворяет требованиям. Это обычная энтерпрайзная разработка, и ни чего сложнее Slick нам пока не требовалось. Своих библиотек мы почти не пишем, а те, что пишем не сложные и относятся в основном к сходным алгоритмам в бизнес-логике.

Да, Scala позволяет писать сложный обобщенный код, который будет потом переиспользоваться в самых неожиданных местах. Писать такой код сложно на любом языке. Но, в отличие от многих других языков, Scala позволяет сделать так, что пользоваться этим кодом можно не вникая в тонкости обобщенного программирования. То есть на Scala просто не только писать что-то простое, но и использовать написанное кем-то сложное. Это очень сильно снижает уровень вхождения, но позволяет при этом быстро расти, осваивая и используя сложные приемы когда они потребуются.
> Язык программирования Scala является «симбиозом» Java и C#

Зачем вы так C# обижаете.
Симбиоз Java и C# это явно Kotlin.

За что этот комментарий заминусили?

Расисты, сэр.
Возможно, дело в том, что заявление, что котлин это симбиоз сишарпа и джавы настолько же глупое, как и то в ответ на которое оно было написано?
По КДПВ:
java версия уже вот так выглядит:
public List<Product> getProducts()
{
    return orders.stream().flatMap(Order::getProducts).collect(toList());
}

(и по-моему это сильно читабельнее)
collect(toList())
это опечатка и должно быть
collect().toList()
или действительно так странно?
Это действительно так странно :)
по идее там должно быть
collect(Collectors.toList())
параметр к методу collect — это то, во что собираем. Так что не так уж и странно.

Автор комментария видимо «статически импортнул» Collectors.toList — поэтому и выглядит странно
Ну мы всегда так делаем, тк это повышает читаемость(Collectors тут не добавляет новой инфы тк он пишется внутри функции с названием collect)
К КДПВ вообще много вопросов. И если
ArrayList <Product>
еще можно объяснить, то
for (Order order : order)

вообще не скомпилируется.
вообще картинка на КДПВ не самая удачная. От нее у людей, не знакомых со scala возникает ложное ощущение что преимущество scala — это просто более удобный синтаксический сахар. Естественно, после этого возникает справедливое замечание, что в 8-й java (которая уже давненько вышла) тоже можно так делать. Но почему-то большинство асторов java vs scala (это я не про TS) забывает про возможно более итересные вещи — неблокирующие future, акцент на immutable данные и тд…
*точнее
return orders.stream().map(Order::getProducts).flatMap(List::stream).collect(toList());

или
return orders.stream().flatMap(o -> o.getProducts().stream()).collect(toList());
НЛО прилетело и опубликовало эту надпись здесь
[offtop] Поражаюсь любви некоторых граждан к дешёвым манипуляциям. Если нужно показать что-нибудь старым и замшелым, пририсуйте ЭЛТ-монитор. [/offtop]
Последнее время в статьях постоянно мелькает некто Барух Садогурский.
Судя по тому, что о нем известно из сети, это больше медиа-персона, чем серьезный девелопер, а название компании JFrog не говорит ничего, равно как и должность Developer advocate.
Я не являюсь профессионалом, код — хобби.
Вполне допускаю, что персона что-то из себя представляет а я что-то упустил, однако насколько стоит ссылаться на его высказывания при оценке ЯП Scala?
Вы объявили поток Product, а надо было метод, возвращающий List. Как-то типы не очень сходятся.
Кому надо было? Во-первых, в скала-версии нет метода, в java-версии я его тоже выкинул. Во-вторых, в скала-версии мы и понятия не имеем, что за типы там используются, а так как java-версию на исходной картинке писал человек явно не знающий джаву, то я взял на себя смелость использовать те типы, которые посчитал нужными. Так что всё с типами хорошо.

В scala-версии как раз метод и объявлен. Вы просто def не заметили.

ваша правда — перепутал def с val. Но надо признать, что метод был бы не сильно больше:
public Stream<Product> getProducts() {
    // если уж совсем честно, то здесь должно быть вот так
    // потому что стримы flatMap-ят только стримы, а getProducts()
    // врядли возвращает Stream
    return orders.stream().flatMap(o -> o.getProducts().stream());
}

Но основной смысл картинки был не в том, что java такой же лаконичный язык как скала, а в том, что исходная картинка пытается показать java-разработчика каким-то атавизмом, в то время как и компьютер у него в действительности такой же, да и язык достаточно современный, пусть и без " тайп-классов на имплиситах".
НЛО прилетело и опубликовало эту надпись здесь
я так думаю, что это зависит от контекста. Возможно, для получения стрима метод лучше было назвать `findProducts()`, но еще раз — сути это никак не меняет — моя картинка была не про язык, а про то, что миф с картинки о том, что скала-программист это такой «факеа», а разработчик на java нелепый старпер — он в корне неверный. Более того, часто это один и тот же человек. А джава хоть и многословный язык, но достаточно современный и имеющий свой подход и концепцию.
НЛО прилетело и опубликовало эту надпись здесь
Тем более, что Scala сама выводит типы и не позволит такой ошибке даже случиться :)
Еще вы как бы заранее завели метод Order::getProducts, а в Scala геттер создается на ходу.
Какой такой? В коде нет никакой ошибки. Один стрим flatMap-ится в другой. Да, вероятно getter ide создала, но это сути передергивания исходной картинки не меняет.
Если сильно нужно, в java есть project lombok, который на препроцессоре аннотаций автоматом создаст вам геттеры. Кода меньше, немного аккуратнее выглядит, но играть с магией — это всегда опасно.

Я последнее время предпочитаю org.immutables:value, несколько удобнее в обращении, работает на том же уровне (annotations processor).

Для Java точнее будет так
Supplier<List<Product>> products = () -> orders.stream().flatMap(e -> e.getProducts().stream()).collect(Collectors.toList());
Меня смущает, что в статье рассказывая о языке Scala автор критикует не сам язык, а его популярность в IT индустрии. И в приведённых цитатах всё больше говорят «рынок», «вакансии», «зарплата». Критика в духе «все деньги в Java» ничего не говорит о качестве Scala. А противостояние Java vs. Scala переводится в сторону корпоративных заказчиков, денежных перспектив и бизнес-проблем. Мне, как программисту, скорее интересно услышать про скорость разработки, про выразительность и краткость, про новые абстракции и улучшенные Generic-классы.
Тот факт, что компания TypeSafe не смогла заработать на продвижении Scala, на мой взгляд говорит лишь о закостенелости рынка Enterprise разработки (Я здесь побуду капитаном-очевидностью), и не должна отпугивать разработчиков от изучения функциональных языков программирования.
В общем, статья скорее для менеджеров, чем для инженеров. А моё ИМХО: есть классный курс «Принципы функционального программирования на Scala», который ведёт сам Одерски.
Все правильно и логично.
И хоть меня закидают помидорами за такое мнение…
Большинству компаний не нужны ни Scala ни развите Java. Им это просто не выгодно. У них есть куча продуктов на старых версиях Java, которые кто-то должен поддерживать и продавать. Для этого нужны люди.
А как можно вообще заманить человека на унылую работу по поддержке легаси?
Ведь не секрет, что большая часть Java проектов до сих пор не вышли даже за Java 6.
Переписывать дорого и не факт что выйдет лучше чем было, плюс риски для клиентов.
Вот и культивируются мысли молодых разработчиков, что в Java все деньги, дергаться не надо, это типа большие риски. Плюс текущая ситуация на рынке, ЗП за легаси платят неплохие.
Все это вместе заставляет очень медленно проворачиваться колесо индустрии в целом.
У этой ситуации нет простого решения, но надо понимать, почему на Scala в основном катят бочку не в техническом плане.
Всегда умиляло, когда нескалисты говорят «да там в восьмой джаве завезли лямбды и стримы, скала больше не нужна». И потом начинают сравнивать map/flatMap в языках. Ну здорово, теперь ламбада-функции есть и в джаве, искренне рад. дукалис.jpg

Вот только никто почему-то не вспоминает про работу с асинхронностью с Future as monad из коробки.

Или про тайп-классы на имплиситах, которые позволяют писать какие угодно дженерик решения для любых
типов (да, да, даже для сторонних, стандартных, whatever, и всё это без оберток).

Или про type-safe парадигму в скале, когда, во многом благодаря той самой «переусложненной» системе типов, можно смотреть на List[Any] или касты .instanceOf как на недоразумение неопытного разработчика.

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

Имхо, тот график с удовлетворенностью разработчиков языком говорит больше, чем вся статья и холивар вокруг.
На моей памяти, это первый язык, который у меня не вызывает приступов ненависти даже спустя три года, что для любой технологии в наше непростое время — невиданное явление.
Или про тайп-классы на имплиситах, которые позволяют писать какие угодно дженерик решения для любых
типов (да, да, даже для сторонних, стандартных, whatever, и всё это без оберток).

Сколько у вас человек в команде?
На одной работе 5 бэкэндщиков.
На другой — 6.

Не вижу корреляции.

Пишу на скале уже два года и ни за что не вернусь обратно. Даже если не лезть в систему типов и имплиситы, которые, имхо, вредны для ежедневного программирования, есть куча мелочей, которые в сумме дают сильный прирост скорости разработки. if/switch/code block as expressions, паттерн матчинг, однострочные объявления методов, сокращенный синтаксис вызова curried functions...


Быть может, когда-нибудь накатаю статью на тему "чем scala лучше с точки зрения промышленного программиста".

Расскажите в двух словах, в чем уникальность «Future as monad» перед аналогичными решениями в java?

тем, что в джаве есть только CompletableFuture, который спроектирован, скажем так, неудачно. И даже если сделали (или сделают) нормальный порт на джаву, то тормозящим фактором станет уже синтаксис:


task1.thenCompose(v1 -> {
  return task2.thenCompose(v2 -> {
    return runTask3(v1 + v2);
  });
});

и


task1.flatMap { v1 =>
  task2.flatMap { v2 =>
    runTask3(v1 + v2)
  }
}

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

соглашусь, что scala-версия выглядит несколько приятнее, но выпячивать эту фичу как весомый аргумент я бы наверное не стал. Тем более, вы написали так, что эта фича есть «из коробки», как будто именно это важно. А из коробки она есть и в джаве, к тому же если я правильно понял, что вы хотели написать, то скорее это будет вот так:

supplyAsync(() -> "test").thenCombineAsync(supplyAsync(() -> "test2"), this::doSomething);


В этом смысле на мой взгляд намного интереснее поддержка continuation-ов в kotlin 1.1, вероятно такой код можно было бы сделать:

val v1 = await(runTask1())
val v2 = await(runTask2())
runTask3(v1, v2)
а если полностью идентичный код, то видимо так:
supplyAsync(this::runTask1).thenCombineAsync(supplyAsync(this::runTask2), this::runTask3);

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

кстати если уже есть task1 и task2, то еще проще:
// как предложил @Sirikid ниже
task1.thenCombine(task2, (v1, v2) -> runTask3(v1 + v2))
task1.thenCombine(task2, Integer::sum).thenCompose(this::runTask3);

по моему опыту использования scala, чаще всего её нужно или использовать как предлагают в best practice и тогда она становится достаточно сложной или java-way и тогда особые преимущества найти сложно, а местами даже скалу использовать менее удобно, например аннотации, которые несовместимы с java-аннотациями.

Ну как сказать… три разных синтаксиса для одной и той же задачи, причем все три специфичны для входных условий. одни хороши, когда у нас переменные, другие — когда функции, третьи — когда лямбды. Обратите внимание, в скале для этой задачи один и тот же синтаксис подходит для всех случаев, и этот синтаксис — прост.


И — откуда вообще мысль, что best practice — сложен? Посмотрите вот сюда: http://twitter.github.io/effectivescala/


Ничего страшного там нет.

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

НЛО прилетело и опубликовало эту надпись здесь

Можно Future.sequence(List(v1, v2)).map(_ + _).flatMap(runTask3)
Но мы же говорим о промышленном коде, а не олимпиадном, не так ли?

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

task1, task2 — это локальные переменные типа CompletableFuture<Integer>


v1, v2 — это, соответственно, Integer


CompletableFuture<Result> runTask3(int arg);

НЛО прилетело и опубликовало эту надпись здесь

Раз уж пошли код сравнивать как можно без lisp в лице Clojure:


(defn task-3 []
  (let [v1 (future (task-1))
        v2 (future (task-2))]
    (future (+ @v1 @v2))))
НЛО прилетело и опубликовало эту надпись здесь
так для однострочников return и скобки не нужны
и
task1.thenCompose(v1 -> {
  return task2.thenCompose(v2 -> {
    return runTask3(v1 + v2);
  });
});

плавно превращается в:
task1.thenCompose(v1 -> 
     task2.thenCompose(v2 ->  
         runTask3(v1 + v2)
     )
);
Например, можно писать так:

for {
  a <- futureA
  b <- futureB
  c <- futureC
} yield {
...
}


Компилятор сам разложит на map/flatMap (можно даже с if подключить filter). Это для начального уровня.

Зайдя чуть дальше в ФП — там Future всё еще монада (ну ладно, тут я лукавлю, она монада, если забыть про эксепшены внутри, иначе left identity не выполняется, но не суть). А значит, можно подрубить монад-трансформеры и работать с Future[Option[A]] словно у вас праздник на улице. В коде ниже мы получаем доступ сразу до значения типа А внутри двух монад:

for {
  a <- futureOptA.optionT //a: A
  b <- futureOptB.optionT //b: B
  c <- futureOptC.optionT //c: C
} yield {
...
}


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

Любопытства ради, хотелось бы увидеть решение на джаве. Слышал, там Option тоже завезли.
НЛО прилетело и опубликовало эту надпись здесь

Не знаю, у меня было совершенно наоборот. Когда меня бросили в скалу, я ее сначала возненавидел, зато потом полюбил. И не за синтаксис, и не за вывод типов, и не за лямбды. А за мелочи, которые делают жизнь проще: Правильным образом перегружаемый == инвариантные массивы, ADT (которые позволяют делать исчерпывающую проверку при паттерн-матчинге), Кейс-классы знатно экономят время. А потом уже стандатный набор всего и вся.

Не понимаю зачем нужны такие статьи, которые создают ложное представление о языке.

Например из цитаты platoff можно сделать вывод, что Scala выбирает неопытная молодежь, хотя на самом деле все с точностью до наоборот. Цитата Баруха тоже не к месту, с чего Вы взяли, что мнение человека из Java/Groovy-мира является экспертным относительно Scala?! (ничего не имею против Баруха, с удовольствием слушаю подскаст всей их тусовки «Разбор полетов», но у него нет экспириенса в этой нише и это просто мнение сбоку по факту). Приведенные рейтинги всяких Teobe, IEEE Spectrum и прочих вообще не отражают реальности: Matlab, R, Asembly выше в рейтинге чем Scala — ага, кулл стори… Судить о языке по количеству вбиваний в гугл и каких-то абстрактных статистик в вакууме — это полнейший бред.
Scala развивается громадными темпами, причем имеется в виду не только сам язык, но и экосистема и востребованность на рынке. Исходя из недавних отчетов stackoverflow.com scala-разработчики одни из самых довольных своей технологией + с одними из самых высоких заработков среди разработчиков. Похожие данные были и от Dou, которые тоже кстати напрямую работают с комьюнити(на Dou просто делаются опросы), а не как Teobe и КО, которые берут данные с потолка.

Создается ложное впечатление, что у Scala все плохо, но перспективы есть. Все совсем не так — для Scala эти перспективы уже настали, сейчас все отлично и продолжает набирать обороты. Эта статья была бы актуальна этак году в 2009ом, но ни как не в текущих тренда и спроса на биг-дейта, анализ данных, распределенных систем и прочего, в чем Scala преуспела.

В статье ни слова про уровень и количество конференций в ФП мире и в Scala в частности. Про положительный экспириенс фирм, которые используют Scala — недавно paypal выкладывали статью о том у них все отлично с Akka. Про крутые проекты/технологии, которые были реализованы на Scala — Spark, Akka, Kamon, Kafka и т.д. О том какие нововведения и перспективы ждут нас в ближайшем будущем — Scala 2.12, Dotty и прочее.

Спрос на Scala весьма хороший в текущих реалиях, о каких “разворотах в сторону Java” вообще идет речь? На Linkedin даже обычным Scala разработчикам постоянно приходят предложения, не говоря уже о Spark специалистах. Еще можно посмотреть тут и сделать выводы: https://jobs.functionalworks.com/

Вообще лучше смотреть кейноты ФП и Scala конференций, чтобы понимать что происходит в ФП и Scala-мире, а не из слов людей знающих о продакшене на Scala чуть меньше чем совсем ничего, набрасывающих и делающих выводы на основе Teobe-рейтингов и говорящих о “смерти” языка из-за обычного переименования Typesafe -> Lightbend…
Вот еще хорошее видео, с объективной оценкой о том “Какое место Scala занимает в IT-индустрии” — https://www.youtube.com/watch?v=jTomnoJ3TyQ
>На Linkedin даже обычным Scala разработчикам постоянно приходят предложения

Это тоже плохой показатель. Он демонстрирует только наличие дефицита — но ничего не говорит о числе предложений.
Как это не говорит, предложения с воздуха по Вашему берутся что ли? Все же просто — какой-либо бизнес выбирает Scala, пилят продукт, растут, ищут новых разрабов. Не пойму в чем тут плохость показателя — в IT всюду дефицит кадров, не успевают специалисты появляться настолько быстро, насколько этого требует рынок.
А вот так и не говорит. Меня, было дело, просто достали с linkedin предложениями поработать над BPM проектом. Раз 10 предлагали. Как вы думаете, сколько было вакансий? Одна. Ее просто не могли закрыть полгода, поэтому всем, у кого в профиле фигурирует BPM, написал каждый не ленивый HR, по одному разу.
Очень узкое место займет — высокий порог входа не для энтерпрайза. Поэтому будет использоваться для отдельных крупных проектов, для которых разработчиков будут искать по всему свету…
НЛО прилетело и опубликовало эту надпись здесь
НЛО прилетело и опубликовало эту надпись здесь
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории