Путеводитель по Scala для Java-разработчиков: Функциональное программирование вместо объектно-ориентированного

Разбираемся как Scala использует преимущества обоих миров

Платформа Java™ исторически была территорией объектно-ориентированного программирования, но даже ярые приверженцы языка Java начали обращать внимание на последнюю, вышедшую из тени, тенденцию в разработке приложений: функциональное программирование. В этой новой серии Тед Ньювард представляет Scala, язык программирования, объединяющий функциональную и объектно-ориентированную техники под управлением JVM. По ходу дела Тед обосновывает, почему следует уделить время изучению Scala — параллелизм одна из причин — и показывает, насколько быстро это может окупиться.

Тед Ньювард, Глава, Neward & Associates

Тед Ньювард - глава Neward & Associates, где он консультирует, руководит, обучает и внедряет Java, .NET, XML Services и другие платформы. Он проживает возле Сиэтла, штат Вашингтон.



05.05.2008

Вы никогда не забудете свою первую любовь.

В моем случае ее звали Табинда (Бинди) Хан. Это были безмятежные годы моей юности, седьмой класс, если быть точным, а она была красива, смышлена и, что самое замечательное, она хохотала над моими неуклюжими подростковыми шуточками. Мы «запали» друг на друга (как это тогда называлось), со взлетами и падениями в отношениях, длившихся преимущественно в 7 и 8 классах. Но к 9 классу мы расстались, это было вежливым способом сказать, что ей надоело на протяжении двух лет выслушивать однообразные и нескладные юношеские хохмы. Я никогда ее не забуду (не в последнюю очередь потому, что мы столкнулись друг с другом снова на 10-летней встрече одноклассников), но что более важно — я никогда не расстанусь с этими заветными (если несколько преувеличить) воспоминаниями.

Об этой серии

Тед Ньювард погружается в язык программирования Scala и берет вас с собой. В этой новой серии от developerWorks вы узнаете вокруг чего поднята такая шумиха и увидите некоторые лингвистические возможности Scala в действии. Код Scala и код Java будут показаны бок о бок, если таковое сравнение будет важно, но (как скоро выяснится) многие вещи в Scala не могут быть напрямую соотнесены с чем-либо таким, что вам знакомо из Java-программирования, но в этом и заключается основное очарование Scala! В конце концов — если Java-код способен это сделать, зачем же утруждать себя изучением Scala?

Java-программирование и объектная ориентированность стали первой любовью для многих программистов, и мы принимаем это с таким же уважением и полным благоговением, как и мое отношение к Бинди. Некоторые разработчики скажут вам, что Java-программирование уберегло их от адских мук в преисподней, порождаемой управлением памятью и C++. Другие скажут, что Java-программирование возвышает их над пучиной процедурной безысходности. Найдутся даже такие разработчики, для которых объектно-ориентированное программирование в Java-коде просто является «изначальной данностью этого мира» (а как же иначе — ведь это работало и при моих предках и при их предках до них самих!)

Однако, время неизбежно преодолевает все первые влюбленности и наступает момент двигаться дальше. Чувства изменились а участники этой истории стали зрелыми (и, будем надеяться, подучили несколько новых шуток), Но более значимо — изменился мир вокруг нас. Многие Java-разработчики осознают, что как бы мы ни любили Java-программирование, пришло время выдвигаться к новым горизонтам на наших «девелоперских» просторах и выяснить, как мы можем все это постичь.

Я буду любить тебя всегда ...

В течение последних пяти лет обозначилась нарастающая волна недовольства языком Java. В то время, как кое-кто может указать на развитие Ruby on Rails как на основной фактор в этом смысле, я приведу доводы что RoR (в нотации, знакомой поклонникам Ruby) является следствием, а не причиной. Или же, выражаясь точнее, докажу, что факт восприятия Java-разработчиками Ruby следует из глубинной, более скрытой причины.

Попросту говоря, в программировании на Java проступает возраст.

Или, что будет точнее, возраст проступает у языка Java.

И действительно: когда язык Java впервые появился на свет, Клинтон (в свое первое президентство) восседал в офисе, а Интернетом регулярно пользовались лишь настоящие энтузиасты, главным образом потому, что соединение по телефонной линии было единственным доступным способом в домашних условиях. Блоги (сетевые дневники) еще не были изобретены, и все верили, что наследование является фундаментальным подходом в повторном использовании. Мы также верили, что объекты являются наилучшим способом моделирования мира и что Закон Мура будет всегда господствовать экспоненциально.

На самом деле — именно законом Мура были в крайней степени озабочены многие в индустрии. С 2002/2003 доминирующей тенденцией в микропроцессорных технологиях было создание процессорных модулей с множеством «ядер»: в сущности, множества процессоров на одном чипе. Это позволяет обойти Закон Мура, который говорит, что скорость процессоров удваивается каждые 18 месяцев. Ситуация с многопоточными средами, исполняемыми на двух процессорах одновременно, вместо того, чтобы выполнять стандартный круговой цикл на едином процессоре, означает, что код должен быть непробиваемой глыбой с точки зрения потокобезопаности, коль скоро такой код претендует на существование.

В академическом сообществе предпринималось множество исследований касательно этой специфической проблемы, приведших к изобилию новоиспеченных языков. Существенным недостатком выступал тот факт, что большинство из этих языков надстраивались над своей собственной виртуальной машиной или интерпретатором, означая таким образом (как делает и Ruby) переход на новую платформу. Кризис параллелизма — настоящая головная боль и некоторые из новых языков предлагают мощные решения, но слишком много корпораций и предприятий помнят миграцию с C++ на платформу Java каких-то 10 лет тому назад. Перемещение на новую платформу — это риск, который многие компании даже не собираются рассматривать всерьез. Многие, в действительности, по-прежнему зализывают раны от последнего перехода на Java-платформу.

Знакомимся со Scala.


SCAlable LAnguage - Масштабируемый язык

Почему Scala?

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

  • Создавать внутренние DSL — типа Ruby, благодаря гибкой реализации идентификаторов в Scala.
  • Создавать в наивысшей степени масштабируемые, параллельные обработчики данных, благодаря тому, что Scala изначально стоит на позициях неизменяемости состояния.
  • Сократить размер эквивалентного Java-кода в половину или на две трети, из-за обилия в Scala синтаксических приемов, таких как замыкания и неявные определения.
  • Использовать преимущества параллельных аппаратных архитектур (таких как многоядерные процессоры), т.к. Scala предрасполагает к функциональному дизайну.
  • Контролировать большие объемы кода, из-за упрощения в Scala правил жесткого типизирования, выставляющих, по существу, одно требование — "все является объектом."

Несомненно — Scala олицетворяет мощный, новый взгляд на программирование; факт компиляции в код, совместимый для запуска под управлением JVM как нельзя лучше позволяет воспользоваться Scala для "настоящей работы", да еще с такой легкостью.

Scala — функционально-объектный гибридный язык с несколькими сильными сторонами, подогревающими интерес к нему:

  • Во-первых, Scala компилируется в байт-код Java, подразумевая его запуск на JVM. В дополнение к вашей возможности продолжать использовать все преимущества Java как развитой экосистемы с открытым кодом, Scala может быть интегрирован в существующее информационное пространство (среду) с нулевыми усилиями на миграцию.
  • Во-вторых, Scala опирается на функциональные принципы Haskell и ML, не отказываясь от тяжкого бремени привычных объектно-ориентированных концепций, столь полюбившихся Java-программистам. В результате Scala может смешивать лучшее из двух миров в единое целое, что предоставляет значительный выигрыш без жертвования простотой, на которую мы привыкли рассчитывать.
  • И в заключение, Scala был разработан Мартином Одерски, возможно, более известным в Java-сообществе благодаря языкам Pizza и GJ, последний из которых стал рабочим прототипом универсальных типов (generics) в Java 5. Раз так, Scala несет ощущение «серьезности»; этот язык не создавался по капризу и он не будет брошен на произвол.

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

Загрузка и установка Scala

Вы можете загрузить комплект поставки Scala с домашней страницы Scala. Текущим на момент написания статьи релизом является 2.6.1-final. Он доступен в виде Java-инсталлятора, пакетов RPM и Debian, архивов gzip/bz2/zip, которые достаточно просто распаковать в целевую директорию, а также в виде исходного tarball, позволяющего выполнить сборку с нуля. (Версия 2.5.0-1 доступна для пользователей Debian с Web-сайта Debian в виде готового к употреблению инсталляционного модуля. Однако версия 2.6 имеет некоторые незначительные отличия, поэтому рекомендуется загрузка и установка напрямую с сайта Scala.)

Установите Scala в каталог по выбору — я пишу это, находясь в среде Windows®, поэтому у меня это будет каталог C:/Prg/scala-2.6.1-final. Задайте этот каталог в переменной окружения SCALA_HOME и добавьте SCALA_HOME\bin к PATH для упрощения вызова из командной строки. Для проверки вашей инсталляции просто запустите "scalac -version". В ответ должно последовать "Scala version, 2.6.1-final".


Функциональные концепции

Прежде, чем мы начнем, я представлю несколько функциональных концепций, необходимых для понимания того, почему же Scala ведет себя так, а не иначе. Если вам доводилось иметь дело с функциональными языками — Haskell, ML или же с недавним пополнением в функциональном мире — F#, вы можете переходить к следующему разделу.

Функциональные языки получили свое название из концепции, предполагающей, что программы должны вести себя как математические функции; другими словами, при заданном наборе входных параметров функция должна всегда возвращать один и тот же результат. Это не просто означает, что каждая функция должна возвращать значение, а и то, что эти функции не должны переносить никакого внутреннего состояния от одного вызова к другому. Такая основополагающая идея несохраняемости состояния, перенесенная в функциональный/объектный мир и означающая объекты, неизменяемые по своей природе — главная причина того, почему функциональные языки провозглашаются великими спасителями безумно параллельного мира.

В отличие от многих динамичных языков, с недавних пор начавших отвоевывать себе пространство на платформе Java, Scala является статически типизированным, как и Java. Однако, в противовес платформе Java, Scala прилагает существенные усилия к использованию выведения типов (type inferencing), означающего, что компилятор выполняет глубокий анализ кода для выяснения типа конкретного значения, без вмешательства программиста. Выведение типа требует меньшей избыточности в типизации кода. Например, рассмотрим приведенный в листинге 1 Java-код, необходимый для объявления локальных переменных и присвоения им значений:

Листинг 1. Ох уж этот гениальный javac ...
class BrainDead {
  public static void main(String[] args) {
    String message = "Зачем указывать javac-у, что message – это строка?" +
      "А что же еще это может быть, если я и так присваиваю String?";
  }
}

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

Множество прочих функциональных особенностей (таких как сопоставление с шаблоном - pattern matching) проложили себе путь в Scala, но полное их перечисление было бы забеганием вперед. Scala также добавляет некоторое количество деталей, отсутствующих на данный момент в Java, скажем, перегрузка оператора - operator overloading (являющаяся, как оказывается, тем, что Java-программисты вообще не могут себе вообразить), универсальные типы (generics) с «верхним и нижним ограничениями по типу», виды (views) и многое другое. Эти особенности, среди прочего, делают Scala чрезвычайно мощным для решения такого рода задач, как обработка или генерация XML.

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


Приступаем

Наша первая Scala-программа будет стандартной демонстрационной программой, Hello World, как того требуют Боги Компьютерных Наук:

Листинг 2. Hello.Scala
object HelloWorld {
  def main(args: Array[String]): Unit = {
    System.out.println("Hello, Scala!")
  }
}

Скомпилируйте это вызовом scalac Hello.scala и запустите полученный код при помощи либо запускающего модуля (scala HelloWorld), либо используя традиционный запуск Java, не забыв включить библиотеку ядра Scala в JVM classpath (java -classpath %SCALA_HOME%\lib\scala-library.jar;. HelloWorld). В любом случае должно появиться традиционное приветствие.

Некоторые элементы в листинге 2 определенно вам знакомы, но также задействованы и некоторые явно новые. К примеру, начав с привычного вызова System.out.println, Scala демонстрирует свою дружественность к лежащей в основе платформе Java. Scala преодолевает огромное расстояние, чтобы обеспечить доступность всей мощи Java в Scala-программах. (В действительности, позволительно даже наследовать тип Scala от Java-класса и наоборот, но об этом позже).

С другой стороны, если вы внимательны, вы должно быть заметили отсутствие точки с запятой в конце вызова System.out.println— это не опечатка. В отличие от Java-платформы, Scala не требует точки с запятой для завершения оператора если это очевидно по факту окончания строки. Тем не менее, точки с запятой по-прежнему поддерживаются и являются иногда необходимыми если, например, физически в одной и той же строке присутствует более одного оператора. В большинстве случаев, прогрессирующие Scala-программисты могут опускать точки с запятой, а компилятор Scala ненавязчиво напомнит вам (обычно посредством броского сообщения об ошибке), когда такой разделитель будет необходим.

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

Ну а теперь давайте взглянем на то, в чем Scala действительно начинает отклоняться от традиционного Java/объектно-ориентированного кода.


Функция и форма — наконец-то вместе

Прежде всего, приверженцы Java отметят, что вместо "class", HelloWorld определен с использованием ключевого слова object. Это поклон Scala в сторону вездесущего шаблона Singleton — служебное слово object сообщает компилятору Scala, что это будет синглетон-объект, и в результате Scala гарантирует, что в любой момент времени будет существовать только один экземпляр HelloWorld. Обратите внимание - по той же причине main не определяется как статический метод, как это было бы в Java-программировании. Фактически Scala избегает использования "static" вообще. Если же приложению необходимо иметь экземпляры некоторого типа наряду с его "глобальным" вариантом, приложение Scala позволит как определение class так и object для одного и того же имени.

Далее, посмотрите на определение main, которое, как и в случае Java-кода, является общепринятой точкой входа для Scala-программ. Это определение, хотя оно и выглядит отличным от такового в Java, идентично: main принимает массив строк в качестве аргумента и ничего не возвращает. Тем не менее, в Scala такое определение несколько отличается от Java-версии. Определение параметра args задано как args: Array[String].

В Scala массивы представлены экземплярами обобщенного класса Array, кроме прочего демонстрирующего то, что Scala использует квадратные скобки ("[]") вместо угловых ("<>") как признак параметризованных типов. Ну и, для полноты картины, отметим использование в языке шаблона "имя: тип".

Как и в случае с другими функциональными языками, Scala требует, чтобы функции (в данном случае метод main) в обязательном порядке возвращали значение. Вот он и возвращает значение "не-значение", называемое Unit. В практическом смысле Java-разработчики могут думать о Unit как об аналоге void, по крайней мере, на данный момент.

Синтаксис для определения метода выглядит весьма интересно, поскольку использует оператор "=", почти так, как если бы выполнялось присвоение тела метода, следующего за идентификатором main. В действительности это именно то, что имеет место: в функциональном языке функции являются концепциями первого рода, как переменные и константы, а, стало быть, и синтаксически интерпретируются как таковые.


Вы сказали замыкания?

Из того, что функции являются концепциями первого рода, вытекает необходимость представления их каким-либо образом в виде автономных конструкций, также известных как замыкания (closures) — понятие, столь горячо обсуждаемое последнее время Java-сообществом. В Scala это легко выполнимо. Прежде чем демонстрировать возможности замыканий, рассмотрим простую программу в листинге 3. Здесь функция oncePerSecond() повторяет свою логику (в данном случае — печать в System.out) каждую секунду.

Листинг 3. Timer1.scala
object Timer
{
  def oncePerSecond(): Unit =
  {
    while (true)
    {
      System.out.println("Time flies when you're having fun(ctionally)...")
      Thread.sleep(1000)
    }
  }

  def main(args: Array[String]): Unit =
  {
    oncePerSecond()
  }
}

Прим.пер.: Практически тройная игра слов: Time flies when you're having functionally – Время летит, пока вы “функциональничаете” Time flies when you're having fun – Время летит, пока вы бездельничаете Time flies when you're having functionally – Время летит, пока вы заняты делом

К сожалению, именно этот код вообще не является функциональным ... или хотя бы практичным. Например, если бы я захотел изменить текст выводимого сообщения, мне бы пришлось изменить тело метода oncePerSecond. Рядовой Java-программист определил бы в oncePerSecond параметр с типом String для передачи такого сообщения. Но даже такой подход крайне ограничен: Любая другая периодическая задача (допустим, пингование удаленного сервера) будет нуждаться в своей собственной версии oncePerSecond— что является прямым нарушением правила "Не повторяйся". Как показано в листинге 4, замыкания предлагают гибкую и мощную альтернативу:

Листинг 4. Timer2.scala
object Timer
{
  def oncePerSecond(callback: () => Unit): Unit =
  {
    while (true)
    {
      callback()
      Thread.sleep(1000)
    }
  }

  def timeFlies(): Unit = 
  { Console.println("Time flies when you're having fun(ctionally)..."); }

  def main(args: Array[String]): Unit =
  {
    oncePerSecond(timeFlies)
  }
}

Теперь ситуация становится интереснее. В листинге 4 функция oncePerSecond принимает параметр, но его тип выглядит странно. Формально, в качестве значения параметра callback принимается функция. Это справедливо до тех пор, пока передаваемая функция сама не имеет входных параметров (обозначено как "()"), и возвращает (обозначено "=>") «ничего» (функциональное значение "Unit"). Далее обратите внимание — в теле цикла я использую callback для вызова переданного в параметре объекта-функции.

К счастью, где-то в программе у меня есть такая функция, а именно timeFlies. Поэтому я просто передаю ее в oncePerSecond при вызове из main. (Вы также заметите, что в timeFlies задействован Scala-специфичный класс Console, служащий для той же цели, что и System.out или же новый класс java.io.Console. Это чисто эстетический вопрос; здесь будут работать и System.out и Console.)


Анонимная функция, какова же твоя функция?

Сейчас функция timeFlies выглядит как нечто бесполезное — после всех усилий у нее, на самом деле, нет другого назначения, как только быть переданной в oncePerSecond. Раз так, я бы вообще не хотел формально ее определять, как показано в листинге 5:

Листинг 5. Timer3.scala
object Timer
{
  def oncePerSecond(callback: () => Unit): Unit =
  {
    while (true)
    {
      callback()
      Thread.sleep(1000)
    }
  }

  def main(args: Array[String]): Unit =
  {
    oncePerSecond(() => 
      Console.println("Time flies... oh, you get the idea."))
  }
}

В листинге 5 функция main передает произвольный блок кода в качестве параметра oncePerSecond, это выглядит как лямбда-выражение из Lisp или Scheme, что, само по себе, является другой разновидностью замыкания. Такая анонимная функция опять демонстрирует мощь отношения к функциям как к гражданам "первого сорта", позволяя вам обобщать код таким совершенно новым способом, не прибегая к механизму наследования. (Поклонники шаблона Strategy, вероятно, уже начали неконтролируемо исходить слюной.)

Но на самом деле, oncePerSecond по-прежнему специфична: она завязана на неразумное ограничение в том, что callback будет вызываться каждую секунду. Я могу дальше продвинуться в обобщении, указав второй параметр, задающий — как часто вызывать переданную функцию, что и показано в листинге 6:

Листинг 6. Timer4.scala
object Timer
{
  def periodicCall(seconds: Int, callback: () => Unit): Unit =
  {
    while (true)
    {
      callback()
      Thread.sleep(seconds * 1000)
    }
  }

  def main(args: Array[String]): Unit =
  {
    periodicCall(1, () => 
      Console.println("Time flies... oh, you get the idea."))
  }
}

Это распространенная практика в функциональных языках: создать абстрактную функцию верхнего уровня, выполняющую некоторую работу, передать в нее блок кода (анонимную функцию) как параметр, и вызвать этот блок кода внутри высокоуровневой функции. Например, при переборе коллекции объектов. Вместо использования в цикле традиционного для Java объекта-итератора, функциональная библиотека предлагает взамен функцию — обычно называемую "iter" или "map" — в коллекционных классах она принимает функцию с одним параметром (объектом, подлежащим итерированию). Таким образом, например, упомянутый ранее класс Array содержит функцию filter, определенную в листинге 7:

Листинг 7. Часть листинга Array.scala
class Array[A]
{
    // ...
  	def filter  (p : (A) => Boolean) : Array[A] = ... // не показано
}

Листинг 7 декларирует, что p— функция, принимающая параметр обобщенного типа A и возвращающая логическое значение. Документация Scala утверждает, что filter "возвращает массив, состоящий из всех элементов исходного массива, удовлетворяющих предикату p." Это значит, что если я захочу на мгновение вернуться к моей программе Hello World и найти все аргументы командной строки, начинающиеся с буквы "G", это будет записано как в листинге 8:

Листинг 8. Привет, люди-G!
object HelloWorld
{
  def main(args: Array[String]): Unit = {
    args.filter( (arg:String) => arg.startsWith("G") )
        .foreach( (arg:String) => Console.println("Найдено " + arg) )
  }
}

Прим.пер.: G-man – агент ФБР

Здесь filter принимает предикат — анонимную функцию, неявным образом возвращающую логическое значение boolean (как результат вызова startsWith()) и вызывает этот предикат для каждого элемента в массиве "args". Если предикат возвращает истина, filter добавляет такой элемент в результирующий массив. После перебора всего массива, результирующий массив возвращается и немедленно используется в качестве исходного для вызова "foreach", который выполняет именно то, что предполагает: foreach принимает другую функцию и применяет ее к каждому элементу массива (в данном случае — просто отображает в консоль)

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

Заключение

Программирование в Scala подкупающе просто и в то же время — необычно. Его простота в том, что вы продолжаете работать с теми же базовыми объектами Java, знакомыми и любимыми вами на протяжении многих лет, а очевидное отличие — в способе, которым вам предлагается осмысливать нисходящую декомпозицию программы на части. В этой первой статье из серии Путеводитель по Scala для Java-разработчиков я лишь бегло ознакомил вас с возможностями Scala. То ли еще будет, а пока — успешного "функционализирования"!

Ресурсы

Научиться

  • Оригинал статьи: The busy Java developer's guide to Scala: Functional programming for the object oriented (EN).
  • Scala Web site: сайт, посвященный языку программирования Scala.
  • "Java EE meets Web 2.0 (EN)" (Constantine Plotnikov, Artem Papkov, Jim Smith; developerWorks, ноябрь 2007г.): статья раскрывает основные несоответствия между платформами Java EE и Web 2.0 и предлагает технологии (в т.ч. Scala), способные решить эти проблемы.
  • "Java theory and practice: Stick a fork in it" (EN) (Brian Goetz, developerWorks, ноябрь 2007г.): абстракция типа fork-join предлагает Java-механизм декомпозиции нескольких алгоритмов, обеспечивающий эффективное использование аппаратного параллелизма.
  • "Functional programming in the Java language" (EN) (Abhijit Belapurkar, developerWorks, июль 2004г.): рассказывает о преимуществах и методах функционального программирования с точки зрения Java-разработчика.
  • Programming in Scala (EN) (Martin Odersky, Lex Spoon, and Bill Venners; Artima, декабрь 2007г): первое книжное издание - введение в Scala, в соавторстве с создателем Scala Мартином Одерски.
  • Технология Java: сотни статей по каждому аспекту Java-программирования.

Получить продукты и технологии

  • Scala: скачайте Scala и начните обучение по материалам этой серии!

Обсудить

Комментарии

developerWorks: Войти

Обязательные поля отмечены звездочкой (*).


Нужен IBM ID?
Забыли Ваш IBM ID?


Забыли Ваш пароль?
Изменить пароль

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Профиль создается, когда вы первый раз заходите в developerWorks. Информация в вашем профиле (имя, страна / регион, название компании) отображается для всех пользователей и будет сопровождать любой опубликованный вами контент пока вы специально не укажите скрыть название вашей компании. Вы можете обновить ваш IBM аккаунт в любое время.

Вся введенная информация защищена.

Выберите имя, которое будет отображаться на экране



При первом входе в developerWorks для Вас будет создан профиль и Вам нужно будет выбрать Отображаемое имя. Оно будет выводиться рядом с контентом, опубликованным Вами в developerWorks.

Отображаемое имя должно иметь длину от 3 символов до 31 символа. Ваше Имя в системе должно быть уникальным. В качестве имени по соображениям приватности нельзя использовать контактный e-mail.

Обязательные поля отмечены звездочкой (*).

(Отображаемое имя должно иметь длину от 3 символов до 31 символа.)

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Вся введенная информация защищена.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=40
Zone=Технология Java
ArticleID=309320
ArticleTitle=Путеводитель по Scala для Java-разработчиков: Функциональное программирование вместо объектно-ориентированного
publish-date=05052008