Моя первая программа… в этот раз на Scala

11 марта 2013

Перепробовав странные и никому на практике ненужные Haskell, OCaml, Perl 6, Common Lisp, Vala, Go, а также немного D, что, впрочем, не было отражено в этом блоге, я решил обратить свое внимание на Scala. Этот язык заинтересовал меня тем, что он отдаленно напоминает OCaml, только без этих ужасных параметризованных модулей, зато с разными плюшками и под JVM, что в последнее время я не склонен считать за недостаток. К тому же, достоверно известно, что на Scala уже сегодня пишут вполне себе реальные проекты, и в их число входит далеко не один только Twitter.

Основные сведения о языке:

  • Scala была создана в 2001-2004 годах в лаборатории методов программирования EPFL, Швейцария;
  • В Scala используется строгая статическая типизация с автоматическим выводом типов;
  • Язык является мультипарадигменным, поддерживаются ООП (где даже функции и примитивные типы являются объектами), функциональное программирование (функции можно использовать в качестве аргументов, есть неизменяемые данные, паттерн матчинг, лямбды, замыкания, каррирование, ленивые вычисления и, конечно же, автоматическая сборка мусора), а также метапрограммирование;
  • В Scala есть изолированные легковесные процессы, как в языках Erlang, Go или D;
  • Несмотря на то, что Scala — компилируемый язык, у него есть интерпретатор и REPL;
  • Код на Scala компилируется в байткод виртуальной машины Java, что есть хорошо, потому что (1) не нужно перекомпилировать программу под 100500 платформ, (2) язык получил проверенные временем GC и JIT-компилятор, (3) в программах на Scala может использоваться куча готовых библиотек, некогда написанных на Java, (4) модули, написанные на Scala, могут быть использованы из кода на Java;
  • Многие программисты небезосновательно полагают, что Scala станет приемником языка Java;
  • Scala используется в Twitter, Яндекс, FourSquare, LinkedIn, Sony, Qiwi, The Guardian, Siemens, Xerox, Novell, PayPal и не только;

В плане числодробления Scala сравнима с Java и Haskell:

Бенчмарк языка Scala

Установка Scala в Ubuntu:

sudo aptitude install openjdk-7-jre openjdk-7-jdk scala

Также нам понадобится sbt (simple build tool). Скачать пакет sbt.deb можно здесь.

Установка во FreeBSD:

sudo portmaster -d java/openjdk7 lang/scala lang/scala-docs devel/sbt

Подсветку синтаксиса Scala для моего любимого Vim я нашел здесь. Заодно открыл для себя Vundle.

Теперь можно запустить программу scala и поделать что-нибдь в REPL:

scala> 1 + 2
res0: Int = 3

scala> List(1,2,res0)
res1: List[Int] = List(1, 2, 3)

scala> :q

В качестве своей первой программы на Scala я решил написать поисковик твитов:

import scala.io._
import scala.util.parsing.json._
import java.net._

object Twitsearch {
  def main(args: Array[String]) {
    if(args.isEmpty) {
      println("Usage: twitsearch <query>")
      return
    }
    val query = URLEncoder.encode(args(0), "UTF-8")
    val url = "http://search.twitter.com/search.json?q=" + query
    val data = Source.fromURL(url).mkString

    JSON.parseFull(data) match {
      case None =>
        println("Failed to parse JSON")
      case Some(j) =>
        val json = j.asInstanceOf[Map[String,List[Map[String,_]]]]
        json("results").map(x => x("text")).foreach(println)
    }
  }
}

Следующая команда запускает программу в интерпретаторе:

scala twitsearch.scala '#scala'

Чтобы скомпилировать программу, а затем запустить ее, следует сказать:

scalac twitsearch.scala
scala -cp . Twitsearch '#scala'

Если вы пишите на Scala программу, которую планируется запускать только в интерпретаторе (другими словами, скрипт), то можете смело опустить объявление объекта-одиночки с методом main. То есть, сразу писать код скрипта, как это делается в Perl или Python. Чтобы не вводить в консоли имя интерпретатора, можно воспользоваться такой оберткой:

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

println("Hello!")

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

  case Some(j: Map[String,List[Map[String,_]]]) =>

… но в этом случае во время компиляции мы получим предупреждение:

warning: non variable type-argument String in type pattern Map[String,List[Map[String,_]]] is unchecked since it is eliminated by erasure

Дело в том, что из-за особенностей JVM на этапе выполнения программы неизвестно, какими типами был параметризован Map. Это называется type erasure и является, бесспорно, существенным недостатком Scala. Для борьбы с ним были придуманы манифесты, тайптэги, а также case-классы. В следующей заметке мы научимся пользоваться сторонними библиотеками, что позволит переписать программу более удачным способом.

Еще один недостаток, который приписывают Scala — это довольно медленная компиляция программ. Недавно я проапгрейдил домашний компьютер, и на нем (Intel Core i7 3.5 GHz с 4-мя физическими ядрами, DDR3 1.3 GHz, SSD) компиляция приведенной программы занимает 3.7 секунды. Многовато, конечно, но жить можно.

Ссылки по теме:

Несмотря на озвученные недостатки, на фоне всего остального разнообразия языков программирования Scala видится мне довольно любопытным вариантом. Я собираюсь поэкспериментировать с ним какое-то время. Посмотрим, что из этого выйдет.

Дополнение: Мои впечатления от языка Scala после года работы с ним

Метки: , , .


Вы можете прислать свой комментарий мне на почту, или воспользоваться комментариями в Telegram-группе.