Но больше дискомфорта приносило даже не то, что я чего-то не понимал, а то что там многое по-другому, да даже тип переменной идет после названия, а порой его вообще нет.
final String str = "abc"; //Java
val str = "abc" // Scala
Вот так описывается функция:
int sum(int a, int b) {return a+b;} // Java
def sum(a: Int, b: Int) = {a + b} // Scala
А еще у Scala есть консоль REPL(Read-eval-print-loop), как, например, в Python. Как вы уже заметили пропали точки с запятой. Можно запускать одностраничные программы без main'а, названия методов и переменных могут содержать и начинаться вообще с любых символов, никаких правил. Там не static, но есть Object, там примитивы тоже объекты, == там на самом деле equals. Если у метода нет параметров то не обязательно ставить точку для вызова метода, скобки тоже опциональны если нет параметров, а если принимает только 1 параметр, то можно написать вот так:
str.charAt(5); // Java
str charAt 5 // Scala
И еще один интересный пример:
val res = 1 + 1
Нет, это не просто 1 плюс 1, здесь у объекта 1, вызывается метод + и ему передается единственным параметром объект 1. Для меня этого было разрывом шаблона.
На помощь моему шоку пришла замечательная книга Дэвида Поллака — Beginning Scala. Книга начинается с одной фразы, после которой я понял что обязательно должен дочитать ее до конца:
Ouch! That hurts my brain! Stop making me think differently. Oh, wait… it hurts less now. I get it. This different way of solving the problem has some benefits. I felt that way after my first year of law school. I felt that way for a while when I began coding Scala.Дэвид имеет колоссальный опыт в программировании, начинал он это дело еще за 20 лет до моего рождения, успел поработать с более чем 10 языками программирования, пока не пришел к Scala. И теперь он говорит:
Scala is a programming language that provides a best-of-all-worlds experience for developers.Тем не менее автор честно предупреждает, что овладеть им не так уж просто, ему для этого потребовалось 2 года, но он надеется, что мы сможем быстрее и он в этом поможет. Это не очень-то простая книга и она предполагает определенный опыт в программировании у читателя. Особенно она понравится тем, кто раньше программировал на Java, т.к. встречается много отсылок к этому языку и можно сравнивать.
Помимо Beginning Scala параллельно я читал уроки Twitter’s Scala School, для всех уроков есть перевод на русский язык, книгу Дэвида Поллака же удалось найти только в английском варианте.
Закрепить теорию помимо самостоятельных путешествий по исходникам скалы и работы помогал проект Scala Exercises, там очень простые задания, но вполне подходят для закрепления какого-то аспекта на первых порах и проверки того, что ты все внимательно прочитал и понял действительно правильно.
И расскажу немного про самые распространенные и очень простые вещи, которые пришлось постичь в первую очередь.
Option. В двух словах — это контейнер в котором либо пусто(None, похоже на null, но имеет методы map, filter, ...), либо лежит какое-то ровно одно значение Some(value) и его использование может сделать код более безопасным и не кидающим NullPointerException, потому что хочешь не хочешь, а чистые данные из Option нужно еще извлечь, и вот в этот момент забыть написать проверку уже сложно.
Конечно, у Option есть метод get, но использовать его не рекомендуется потому что в этом случае теряется весь смысл Option, т.к. None.get вызывает исключение.
Несколько самых очевидных удобств:
Легко возвращать значение по умолчанию в случае пустого Option
optValue.getOrElse(defaultValue)
В случае каких-то действий:
optValue match {
case Some(value) => action
case None => defaultAction
}
Пример из Scala Beginning. Путь есть некая база данных, которая содержит записи типы Person
def findPerson(key: Int): Option[Person]
Метод вернет Some[Person] если такая запись будет найдена и None иначе.
Теперь мы хотим получать возраст пользователя по ключу.
def ageFromKey(key: Int): Option[Int] = findPerson(key).map(_.age)
Нам не пришлось тестировать на None и метод получился очень лаконичным.
Pattern matching. В начале я подумал, что это тот же джавовский switch и использовать я его почти не буду, но это не так. В Scala это одна из самых часто используемых конструкций.
Приведение типов:
obj match {
case str: String => str
case number: Int => number
}
Можно добавить дополнительные условия и добавить действие по умолчанию
obj match {
case strWithA: String if strWithA.contains("a") => strWithA
case negative: Int if negative < 0 => negative
case zero if zero == 0 => zero
case _ => defaultAction
}
Крайне удобно использовать pattern-matching с case-классами. Пример из Scala Beginning
Stuff("David", 45) match {
case Stuff("David", age) if age < 30 => "young David"
case Stuff("David", _) => "old David"
case _ => "Other"
}
Функции
Начнем с того, что в Scala функции — это инстансы, реализующие определенный интерфейс, а точнее trait FunctionX, где X это количество параметров и принимает значение от 1 до 22. В этом трейте единственный метод — aplly, который и вызывается для функции. Поскольку функции это обычные инстансы, то мы можем передавать и возвращать их из методов и функций.
Пример из Scala Beginning. Передаем в answer какую-то функцию из Int в String, а она возвращает результат работы этой функции с параметром 42.
def answer(f: Function1[Int, String]) = f(42)
или что тоже самое
def answer(f: Function1[Int, String]) = f.apply(42)
Очень удобная вещь функциональные комбинаторы/
Оставить в массиве только положительные элементы:
arr.filter(value => value > 0)
Чуть более сложный пример. Посчитать сумму значений функции f от положительных элементов списка. 2 способа это сделать:
list.filter(x => x > 0).foldLeft(0)(_ + f(_))
list.filter(x => x > 0).map(f).sum
А в конце хотелось бы сказать зачем вообще я все это написал. Я не хотел никого учить Scala или рассказывать о языке как о таковом, таких статей на хабре и в интернете достаточно много, и многие очень хорошие и полезные. Моей целью было просто рассказать свою историю, которая кому-то может быть интересна и сможет помочь и поддержать какого-нибудь такого же потерянного новичка, которого судьба только-только столкнула с этой скалой. Желаю тебе удачи! Опытных же программистов призываю поделиться в комментариях своими советами и мнениями, на счет пути начинающего Scala-программиста.
Комментарии (39)
Focushift
06.04.2019 02:26Чтото это мне напоминает… слабую типизацию в JS и другие «нюансы».
Но JS принято хаять, а тут прям как манна небесная все эти возможности запутать код.vchslv13
06.04.2019 05:22Кто Вам сказал, что она слабая? Я не знаю Scala, но судя по Вики и моему знакомству с Хаскелем, типизация у Scala как-раз таки строгая статическая с выводом типов.
Focushift
06.04.2019 13:17Т.е. вот это правильно и все так должны делать?
str charAt 5
Пример повышенной читабельностиstuf4ik
06.04.2019 15:36Чтото это мне напоминает… слабую типизацию в JS и другие «нюансы»
Scala является strong static type языком. За механизм вывода типа отвечает компилятор, если вы не указываете его явно.
Т.е. вот это правильно и все так должны делать?
Все зависит от вашего style guide. Но обычно такой вызов метода, в infix notation, не используется. Предпочитают более явный: str.charAt(5)olexandr17
06.04.2019 16:16тогда и 1+1 можно писать, как 1.+(1)
я изучал скалу полторы недели и да, некоторые шаблоны мышления успели порваться )
borv
06.04.2019 18:23+1Эта форма используется часто для DSL. В скале это одна из киллер фич. Вы описываете свои операторы для своего языка который вам подходит, получаете максимально выразительный код практически без boilerplate. Не все, конечно, ложится, но для всяких систем правил, ETL и прочего — очень удобно. Когда вы пишете просто императивный код есть соглашение, что когда есть символьные имена используется операторная нотация, а когда нет — обычная через "точку".
javax
06.04.2019 07:44+2В Java есть Optional, REPL и функции как инстансы. Сюрпрайз.
А вообще — удачи!sshikov
06.04.2019 09:36Собственно, после этого можно было не читать уже. Есть, и давно. Не говоря уже про то, что сторонние реализации Option существуют с момента появления generics.
javax
06.04.2019 09:38+5Давайте будем снисходительны. Джиниор, думал, что знает Джаву, открыл для себя Скалу, решил поделиться. Ну что плохого то? :)
sshikov
06.04.2019 09:52+1Ну, особо плохого в том, чтобы чего-то не знать, конечно нет. Но понимать, что ты еще почти ничего не знаешь, вообще говоря стоит. У меня несколько двоякое впечатление — с одной стороны, явных ляпов нет, текст нормальный, а с другой — автор явно в глаза не видел Java 8 и новее.
С точки зрения автора — все хорошо. С точки зрения читателя — еще один, сто десятый пост о том, что существует такая штука, как fold?sievmi Автор
06.04.2019 10:43Конечно же я это прекрасно понимал, когда писал эту статью :) И мне казалось, явно это дал понять в ней, призывая опытных ребят делится советами с тем, кто только начинает.
Вообще говоря, статью я писал 2 года назад и уже давно забыл про нее. Сейчас за нее немного стыдно)
Но, тем не менее, главная цель — поделиться впечатлениями новичка и рассказать свою историю о том, как пробовал учиться. Для таких же новичков. Если бы я в то время нашел такую статью, мне было бы 100% интересно.sshikov
06.04.2019 10:51+1А отчего же сейчас немного не переписать, если вы понимаете недостатки?
sievmi Автор
06.04.2019 11:03А зачем искажать впечатление? Тогда я думал и знал именно то, что написал. Если сейчас что-то исправлять, то получится уже рассказ совсем от другого человека. Что идет в разрез с тем, ради чего я ее тогда хотел написать.
А про всякие технические неточности и т.п. уже написали, или напишут, в комментариях.
Повторюсь, цель — рассказать историю. А переписывать историю не круто)sshikov
06.04.2019 11:44Речь в общем не про переписывание истории, а про новый взгляд на историю из сегодняшнего дня. Это вполне могло бы быть интереснее.
solver
06.04.2019 12:41С одной стороны как бы да, вроде ничего плохого…
А с другой стороны, такого материала просто завались в интернете.
Он не добавляет вообще ничего к теме изучения, увеличивает данные при поиске инфы.
Но самое главное! Такие статьи банально вводят в заблуждение неточностью информации. Что порождает чудовищное количество мифов во круг языков вообще и скалы в частности.
Ведь никто не будет править статью, вносить изменения, уточнения и т.д. Она так и будет, извините, «засирать» головы начинающим разработчикам, у которых еще не сформировалось критическое мышление в отношении языков программирования.
ИМХО Таким статьям место в личном бложике, а не на популярных ресурсах.
george3
06.04.2019 09:11+1Главная фишка для простого программиста — ее Collections. Там есть immutable collections весьма полезные для параллельного и всякого другого программирования-моделирования где большие данные ветвятся на альтергативные варианты. Т е для реально чего-то сложного. Для обычных бизнес-приложений писать на Scala как ездить на танке в булочную. Прикольно но разницы с велосипедами-мопедами(Go, Kotlin,C#, Python, ..) особой нет.
Optik
06.04.2019 09:41+11. Вот уж параллельные коллекции использовать не надо. Их выпилят в 2.13.
2. Сравнение с танком странное. Если использовать как better-java, то разницы не особо — синтаксис и еще одно стдлиб. Если использовать фп, ну это как раз для бизнес-приложений отлично. Гарантий больше, тестов меньше.george3
06.04.2019 11:24Про параллельные коллекции не заикался. А фп которое поверх коллекций весьма замедляет код, чем в тупую циклы как напр. на Go. Не умеют они их там умно разворачивать, а в новой 2.13 реализации как показывают тесты замены на VIEW варианты(которые там по умолчанию) еще замедляют а не ускоряют код. (P S Для меня Scala №1)
tuxi
06.04.2019 12:00Option. Такого в Java нет. В двух словах — это контейнер в котором либо пусто(None, похоже на null, но имеет методы map, filter, ...),
В java иногда (я первый раз в живом коде увидел в 2005 году) применяют паттерн создания статик инстанса объекта с именем NULL. И в методах, где возвращается экземпляр обьекта этого класса, если по ряду причин неудобно кидать эксепшен, возвращают этот NULL. Не всегда применимо, но частенько спасает. Особенно при всяких ETL операциях. Скала походу оттуда это взяла. Вкупе с паттерном «возвращать список» ваще сильно устойчивая ко всяким неожиданностям архитектура получаетсяmaxzh83
06.04.2019 13:03применяют паттерн создания статик инстанса объекта с именем NULL
Выглядит как царь-костыль.
Скала походу оттуда это взяла.
Маловероятно, в Scala много чего пришло из Haskell и других ФЯ. Посмотрите там Maybe, очень похоже. Ну а потом, уже видимо из Scala, это перекочевало в Java 8 в виде Optional.tuxi
06.04.2019 13:30Любой паттерн применяемый везде, где надо и где не надо — станет царь-костылем
Описанный мной паттерн удобно использовать, когда нужно замапить внешние данные в какую либо внутреннюю структуру и при этом нет большого смысла сообщать о нечастых ошибках во входных данных или о том, что незначительно изменилась их структура.
Хотя бы потому, что никаких движений по их исправлению не будет, грубо говоря, заказчика вполне устраивает если будет успешно преобразовано 60..70% входных данных из большой иерархической структуры. Вот там такие «заглушки» вполне к месту.
fshp
06.04.2019 23:30Костыль, костыль.
None это синглтон типа Option[Nothing].
Nothing это синтетический костыль-тип, являющийся подтипом для любого типа. Другими словами Nothing наследуется вообще от всего и сразу.
Option ковариантен. А значит Option[Foo] является супертипом (родителем) для None: Option[Nothing].
Именно ковариантность позволяет использовать None с Option любых типов.
Благо все это существует лишь в разуме компилятора. А потом хренакс: привет стирание типов и Option[Object].
den_po
06.04.2019 15:40Ну совсем же не похоже — экземпляр класса vs пустая коллекция. Больше похоже на nullable объекты, только проверки на null легко потерять, а в Option/Optional тип хоть не совсем строго, но поощряет правильное использование.
maxzh83
06.04.2019 20:30Ну совсем же не похоже — экземпляр класса vs пустая коллекция.
Не совсем понял, что не похоже? Где экземпляр класса? Где коллекция?den_po
06.04.2019 22:45Экземпляр — NULL в комментарии tuxi, коллекция — Option.
tuxi
06.04.2019 23:20я спецом сразу написал в конце комментария
Вкупе с паттерном «возвращать список» ваще сильно устойчивая ко всяким неожиданностям архитектура получается
Речь про паттерн «всегда возвращаем список», то есть: нет результата — возвращаем пустой список.
androidovshchik
06.04.2019 12:54Я незнаком со Scala, но интересно, почему она в свое время не взлетела как Kotlin для андроида? По примерам из публикации лично у меня никакого дискомфорта нет и вроде как тоже меньше кода пишешь, удобнее
maxzh83
06.04.2019 13:10Очень тяжелая во всех смыслах. И для запуска на андроиде и для вхождения в язык широких масс, да и для тулинга тоже. Просто в статье много чего не описано, от этого кажется, что все просто. Посмотрите, например, на библиотеку scalaz, там все поинтереснее. Может возникнуть вопрос: а зачем мне эту дичь использовать? Ответ: вы может и не будете, но кто-то в вашей команде может. То есть, одну и ту же задачу в Скале можно решить множеством способом: и в стиле Java+ и в стиле Хаскеля. Это очень круто, но предъявляет повышенные требования к организации гайдов для кодинга и т.д.
0xd34df00d
06.04.2019 15:53Scala is a programming language that provides a best-of-all-worlds experience for developers
Понятно, что всяк кулик свое болото хвалит, но ровно это делает для меня скалу неюзабельной. Уж лучше императивное на плюсах, функциональщину на хаскеле или идрисе.
freezlite
Извините, но именования переменных и функций не очень то сбивающе с толку выглядит