Программист Scala - «должен ли быть один очевидный способ сделать это» или «более чем один способ сделать это»? - PullRequest
15 голосов
/ 05 февраля 2010

Я давно занимаюсь Java и начал заниматься Scala около 6 месяцев назад. Я люблю язык. Одна вещь, которую я обнаружил, состоит в том, что есть несколько способов сделать что-то. Я не знаю, связано ли это с природой языка или с тем, что он все еще молод и развивается, а идиомы и лучшие практики не появились.

Что меня удивляет, так это то, что я всегда был человеком на языке perl, где:

«Должен быть один - и желательно только один - очевидный способ сделать это».

имеет для меня больше смысла, чем

«Есть несколько способов сделать это» .

Мне интересно узнать, где, по вашему мнению, подходит Scala в этом масштабе и почему?


Котировки: Python PEP20 и Цитата Perl

Ответы [ 6 ]

19 голосов
/ 05 февраля 2010

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

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

val array = Array(1,2,3,4,5)
var sum = 0
var index = 0
while (index < array.length) {
  sum += array(index)
  index += 1
}
sum

Существуют также общие функциональные подходы, которые работают медленнее при работе с примитивами (это может измениться с @ special в 2.8), но оставят вам меньше утомительного:

var sum = 0
Array(1,2,3,4,5).foreach(x => sum += x)
sum

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

Array(1,2,3,4,5).reduceLeft( _ + _ )

И иногда есть очень не общие конструкции, которые делают именно то, что вы хотите; в Scala 2.8, например:

Array(1,2,3,4,5).sum

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

5 голосов
/ 05 февраля 2010

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

  • Объект ориентации * +1008 *
  • Функциональное программирование
  • Java-специфичные подходы
  • Языково-ориентированное программирование (расширение синтаксиса, метапрограммирование)

Это позволяет программисту решать проблемы с разных точек зрения и, следовательно, разными способами. Как вы и подозревали, это в самой природе языка (как и в других универсальных / мультипарадигмальных языках).

Какой из них использовать, во многом зависит от программиста, хотя я могу дать некоторые общие правила / мысли:

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

  • Будьте последовательны! В конце концов, для вас должен быть один путь , но вы можете выбрать какой . Избегайте смешения побочных эффектов и чистых функций, списочных и библиотечных функций (карта, фильтр) или Java-функционального мышления. Вместо этого используйте разные парадигмы ортогонально там, где они лучше всего служат.

  • Используйте замечательные функции, которые Scala предоставляет вам (а не просто используйте его как Java с приятным синтаксисом): сопоставление с образцом, продолжения, универсальные шаблоны и чрезвычайно мощная система типов, высший порядок функции.

4 голосов
/ 05 февраля 2010

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

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

Несколько исключений в основном являются следствием высокой ортогональности. Вещи в Scala не запрещены, потому что они не имеют смысла (с точки зрения дизайнера) или неоптимальны.

И, наконец, акцент на библиотеках. У Scala нет списков или карт. И массивы указываются только потому, что для этого требуется совместимость с Java. В этом смысле он очень похож на C, в отличие от BASIC. В C почти все, что вы делаете, кроме математики, делалось с помощью библиотек, написанных либо на самом C, либо на ассемблере. В бейсике даже такие команды, как открытие файлов или отображение текста на экране, являются частью самого языка.

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

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

Например, List имеет оператор добавления (в Scala 2.8), хотя это неоптимально для списков. У него есть это, потому что List - это Seq, и это обычная операция, которую вы можете захотеть сделать с ними.

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

2 голосов
/ 05 февраля 2010

Самым очевидным местом, где scala предлагает совершенно разные способы достижения одного и того же, является область for понимания:

val ls = List(1, 2, 3, 4)
for (l <- ls) println(l) //for comprehension
ls.foreach(println(_))   //underlying form 

Это распространяется на flatMap, filter и т. Д. Мой личный выбор - придерживаться вызовов методов, хотя в более сложных примерах, таких как:

for (i <- 1 to 10;
     j <- 1 to 20 if (j % 2 == 0)) ...

Я вижу, что они более просты и интуитивно понятны в форме for. Я ценю умение выбирать свой стиль, потому что люди разного происхождения предпочитают разные вещи.

Добавление конструкций управления к 2.8 подобно Exceptions является тому примером: исходя из фона Java, я сначала не получил всю мощь этих абстракций, но если бы я начал в функциональной стране я бы, наверное, сразу понял.

Моя главная ошибка в Scala - отсутствие разумного понимания предиката в классе option. Хотя для некоторого предиката p:

opt.isEmptyOr( p ) //does not exist
opt.forall( p )

Это эквивалентно, мне не нравится тот факт, что первое не существует с точки зрения читабельности. Точно так же:

opt.notEmptyAnd( p ) //does not exist       
opt.map(p).getOrElse(false)

На мой взгляд, 2-я форма неоправданно не читается! Дублирование для достижения читабельности , безусловно, положительно!

1 голос
/ 05 февраля 2010

Отказ от ответственности: я понятия не имею, что об этом думают авторы Scala, я просто выражаю свое мнение как разработчик scala (и python и ruby).

Проходя через Scala API, вы не видите много способов сделать то же самое. Например, изменяемые и неизменяемые версии объектов имеют одинаковый интерфейс. Такие вещи придают Скале некоторую согласованность.

Будучи гибридным языком, обычно есть два пути решения проблемы: функциональный и процедурный (foreach против for). Конечно, если вы хотите использовать процедурный способ, вы просто будете использовать Java.

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

Наконец, я считаю, что любой код должен быть очевидным для чтения. И очевидно, чтобы написать. Вы можете быть очень гибким (perl / ruby) или строгим (python). Scala - гибкая программа это очевидный путь.

1 голос
/ 05 февраля 2010

Все это понятие настолько расплывчато, что в значительной степени бессмысленно. Но я подозреваю, что если бы вы работали с языком, на котором действительно был только один способ сделать какую-то вещь, вы бы вопили и скрежетали зубами по крайней мере в 50% случаев.

Мое (смутное) ощущение, что на любом приличном языке программирования общего назначения, всегда будет много способов для достижения большинства вещей.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...