Scala. Введение

    Привет хабралюди.

    Не так давно я заинтересовался одним из многочисленных ныне языков под JVM — Scala. Причин тому много, основная — всё нарастающее со временем чувство неудобства при работе с cpp-подобными языками. Взгляд мой попеременно падал на Ruby, Groovy, Python, но все они оставляли впечатление инструментов, не совсем подходящих для моего обычного круга рабочих задач (Python-таки хорош, но у нетипизированных языков есть свои ограничения). Scala же, напротив, показалась вполне годным языком. Так как поиск по хабру никаких статей о ней не выловил (было несколько, но мягко говоря не вводных), я решил написать маленький обзор и поделиться им с массами.

    Немного философии языка в вольном изложении


    Какие основные цели преследовали создатели языка? Согласно моим мироощущениям они такие:
    Во-первых, совместимость. Среди своих задач разработчики ставили поддержание совместимости с Java-языком и тысячами примеров говнокода разработок на ней для решения самых разнообразных задач.
    Во-вторых, интенсивное насыщение языка функциональными фичами, которые, в основном, (но далеко не полностью) составляют его отличия от Java.
    В-третьих, облегчение нашего с вами труда. Действительно, компилятор Scala понимает программиста с полуслова, писать код специально, чтобы втолковывать ему, что я не верблюд, мне не довелось пока.
    В-четвёртых, поддержка и стимулирование написания модульных, слабосвязанных программных компонентов в сочетании с широкими возможностями адаптации уже существующих. Цели не то, чтобы совсем противоположные, но порождающие известные трудности для одновременного достижения. Что ж, посмотрим что получится.
    В-пятых, это поддержка параллелизма. К сожалению у меня руки и голова до этой области не дошли (надеюсь пока), но акцент на этом моменте делается постоянно на всех ресурсах по языку.

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

    Итак, давайте посмотрим на сам язык…

    Общие идеи языка, примеры синтаксиса


    Самое, пожалуй, важное, — это «унифицированная модель объектов». Этот термин расшифровывается авторами так: «каждое значение — объект, каждая операция — вызов метода». Это, конечно, не «всё — объект», но сущностей в сравнении с Java убыло, а чем меньше сущностей — тем легче жизнь :) В прикладном плане это означает, что числа и символы сделались неизменяемым объектами, обитающими в общей куче, все операции приобретают ссылочную семантику. Например, код 5 + 5 вполне валиден, и породит новый объект в куче, который оперативненько оприходует сборщик мусора (на самом деле, я тихо надеюсь, что компилятор поймёт глубину замысла и порождать он ничего не будет :) ).

    После столь возвышенного введения можно глянуть на решение классической задачи:
    object Main {
     def main(args:Array[String]) :Unit = {
      print("Hello, " + args(0) + "!")
     }
    }


    В нём мы видим следующее:
    • Можно объявлять отдельные объекты. Ничего необычного в этом нет, подобная возможность имеется, например в Groovy. Ведут себя такие объекты так же как написанные на Java реализации шаблона Singelton.
    • Объявление фукции выглядит непривычно, но вполне читабельно: [ключевое слово def] [имя]([список параметров]):[возвращаемый тип] = [блок кода].
    • В качестве типа, не несущего информационной нагрузки, выступает тип Unit. Он вполне аналогичен void в C-подобных языках.
    • Объявление параметра функции (а на самом деле и локальной переменной тоже) выглядит как [имя]:[тип].
    • Для параметризации типа используется не привычные нам <>, а казалось бы, навсегда закреплённые за масивами [].
    • Для обращения к элементам массива(экое непотребство) используются ().
    • Имеется какие-то встроенные функции, доступные в коде по умолчанию без всяких дополнительных импортов.

    В дополнение, давайте взглянем на ещё один короткий пример:
    println( ("Hello, " + args(0) + "!").toUpperCase )
    println( "Hello, " + args(0) + "!" toUpperCase )


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

    В качестве подспорья разработчику Scala поддерживает также интерактивный режим. То есть, можно запустить интерпретатор и по одной вводить комманды. Интерпретатор, встроенный в IDE, как-то нерегулярно работает, его отдельный вариант есть в репозитариях Убунты, думаю у остальных дистрибутивов тоже всё хорошо, счастливым обладателям Windows как всегда придётся помучаться :) Интерпретатор запускается самым необычным способом:
    $ scala
    Welcome to Scala version 2.7.3final (Java HotSpot(TM) Server VM, Java 1.6.0_16).
    Type in expressions to have them evaluated.
    Type :help for more information.
    scala>

    Совсем маленький пример:
    scala> 1 to 10
    res0: Range.Inclusive = Range(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)

    Тут мы видим пример вызова метода с параметром. Если кто не догадался, у объекта класса Int 1 вызывается метод to с параметром того же типа 10, результат — диапазон значений.

    Попробуем-ка мы теперь написать ещё одну функцию. Пусть она нам считает сумму чисел в заданном диапазоне, итак:
    scala> def sum(a: Int, b: Int): Int = {
    | var result = 0
    | for (i <- a to b) result += i
    | result
    | }
    sum: (Int,Int)Int

    scala> sum(1, 5)
    res3: Int = 15

    Здесь видны ещё три важных момента:
    • При помощи ключевого слова var мы можем объявлять локальные переменные
    • Результатом вычисления блока является последнее выражение в нём
    • В нашем распоряжении имеется цикл for, который может выполнять вычисления для значений в заданном диапазоне (на самом деле для объектов в любом объекте — контейнере)

    Операции над функциями


    Что же мы такого можем с ними тут делать? Да что угодно =) Функции являются полноценными объектами программы. Их можно хранить как свойства объектов, передавать как параметры и возвращаемые значения и собственно создавать во время выполнения. Данные свойства позволяют строить так называемые функции высокого порядка, оперирующие себе подобными.

    Для иллюстрации рассмотрим ставший классическим пример вычисления суммы:
    scala> def sum(f: Int => Int, a: Int, b: Int): Int =
    | if (a > b) 0 else f(a) + sum(f, a + 1, b) sum: ((Int) => Int,Int,Int)Int

    В данном примере определяется функция sum, представляющая знакомый, надеюсь, всем оператор суммы. Параметры имеют следующий смысл:
    f — функция преобразования целого числа из пределов суммирования в элемент суммы. Обратите внимание на объявление типа параметра: знак => означает, что параметр — функция, типы принимаемых значений перечисляются слева от него в круглых скобках (если параметр один, как в данном примере, их допустимо опустить), тип возвращаемого результата справа.
    Работает она тривиально: вычисляет значение функции в нижней границе диапазона и складывает его с результатом вычисления себя самой в диапазоне на 1 меньшем.
    Также в этом примере видна ещё одна особенность языка — if является выражением, имеющим значение (кстати, использованный ранее for — тоже выражение, его результат типа Unit). Если условие истина, то его результат первый вариант, иначе — второй.
    a и b — пределы суммирования.

    Ещё пара функций id и square, они равны своему параметру и его квадрату соответственно.
    scala> def id(x: Int): Int = x
    id: (Int)Int
    scala> def square(x: Int): Int = x * x
    square: (Int)Int

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

    Теперь можно воспользоваться тем, что мы написали ранее.
    scala> sum(id, 1, 5)
    res1: Int = 15
    scala> sum(square, 1, 5)
    res2: Int = 55

    Здесь происходит кульминация этой части — мы берём и передаём функцию в другую функцию. Никаких интерфейсов, анонимных классов, делегатов: вот оно — маленькое счастье.

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

    Особенности классов


    Давайте опишем несложный класс. Пусть это будет комлексное число. Создадим следующий код:
    class Complex(r: Double, i: Double) {
     def real = r
     def image = i
     def magnitude = Math.sqrt(r*r + i*i)
     def angle = Math.atan2(i, r)
     
     def + (that: Complex) = new Complex(this.real + that.real, this.image + that.image)
     
     override def toString = real+" + i*"+image+" | "+magnitude+"*e^(i*"+angle+"))"
    }

    object Main {
     def main(args:Array[String]) :Unit = {
      val first = new Complex(1, 5)
      val second = new Complex(2, 4)
      val sum = first + second
      println(first)
      println(second)
      println(sum)
     }
    }


    Во-первых, клас объявлен с какими-то параметрами. Как несложно догадаться по продолжению, это параметры конструктора, которые доступны всё время жизни объекта.
    Во-вторых, в классе объявлено несколько методов — селекторов. Одно семейство для декартового представления и одно для полярного. Как видим оба они используют параметры конструктора.
    В-третьих, в классе объявлен оператор сложения. Объявлен он как обычный метод, принимает также Complex и возвращает его же.
    Ну и наконец, для этого класса переопределена, без сомнения, знакомая всем Java-программистам функция toString. Важно отметить что на переопределение методов в Scala всегда необходимо явно указывать при помощи ключевого слова override.

    Несмотря на огромную практическую ценность данный класс обладает рядом недостатков, а именно:
    • Занимает неоправданно много для своей функциональности места на экране
    • Не умеет сравнивать себя с себе подобными

    Что же, попробуем исправить недочёты, средствами этого прекрасного языка.
    class Complex(val real: Double, val image: Double) extends Ordered[Complex] {
     def magnitude = Math.sqrt(real*real + image*image)
     def angle = Math.atan2(image, real)
     def + (that: Complex) = new Complex(this.real + that.real, this.image + that.image)
     def compare(that: Complex): Int = this.magnitude compare that.magnitude
     override def toString = real+" + i*"+image+" | "+magnitude+"*e^(i*"+angle+"))"
    }

    object Main {
     def main(args:Array[String]) :Unit = {
      val first = new Complex(1, 5)
      val second = new Complex(2, 4)
      if (first > second )
       println("First greater")
      if (first < second )
       println("Second greater")
      if (first == second )
       println("They're equal")
     }
    }


    Итак, что появилось нового:
    • У параметров конструктора появилось ключевое слово val и исчезли соответствующие селекторы. Да, всё вполне очевидно, это разрешение компилятору создать селекторы для них автоматически.
    • Добавилось наследование от незнакомого нам класса (а точнее trait'а) Ordered. Да не простого, а параметризованного нашим классом. Как следует из названия, он должен помочь нам с упорядочиванием наших экземпляров.
    • Появился метод compare, который сравнивает два комплексных числа посредством сравнения их модулей.
    • В тестовом методе появились использования операторов >, <, ==. Их мы явно не определяли.

    Пришло время сказать несколько слов об идее trait'а. Это особый тип класса, который не может иметь конструкторов, но может иметь любые методы и аттрибуты. Обычно они устанавливают некоторый протокол для взаимодействия со своими возможными наследниками. Используя этот протокол они могут получить необходимую информацию от потомка и реализовать в нём некоторое поведение. Соответственно, любой класс (или объект) может наследоваться от произвольного количества trait'ов(и лишь от одного class'а). Например Ordered объявляет абстрактный метод compare и на его основании дополняет класс-наследник операторами <, <=, > и т.д. Здесь надо заметить, что по-хорошему стоит переопределить предоставленный нам оператор ==, так как он даёт истину и для неодинаковых объектов, да и методы equals с hashCode также стоит переопределять в таких случаях.
    «Всё это хорошо» — скажет бывалый боец аутсорсерного рынка, «но что делать если требуется банальный domain-класс, с богомерзкими модификаторами атрибутов?».
    Решение у нас, естественно, есть :)
    class User {
     private[this] var _name: String = ""
     def name = _name toUpperCase
     def name_=(name: String) = {
      _name = if (name != null) name else ""
     }
    }

    • Во-первых, этот класс использует уже знакомое нам ключевое слово var в своём теле, да не просто а с диковинным модификатором private[this]. Значение этого ключевого слова в теле класса абсолютно аналогично таковому в внутри блока(и даже, скажу по секрету, в конструктор его тоже можно запихать) и делает из имени после него изменяемый аттрибут класса. Диковинный модификатор заявляет, что переменная должна быть доступна только данному объекту. Можно было написать, например, private[User] и она стала бы доступна другим, нам подобным, объектам, или указать имя пакета (что-то это мне напоминает).
    • Далее объявлена функция возвращающая наше поле в верхнем регистре.
    • И в заключение, странная функция name_=, получающая строку в виде параметра, проверяющая что она не null и записывающая её в наше поле.

    Чтобы понять, как это всё использовать давайте взглянем на результат выполнения следующего кода(для краткости я не стал включать сюда описание объекта и main-метода):
    val user = new User("Scala!!!")
    println(user.name)
    user.name = "M. Odersky"
    println(user.name)

    SCALA!!!
    M. ODERSKY


    Внимание, вывод: метод с именем <что-то>_= вызывается при использовании конструкции <объект>.<что-то> = <что-то другое>. Насколько я знаю в Scala это второй хак (первый — преобразование () в вызов метода apply), как Гвидо завещал c неявным преобразованием использования оператора в вызов метода.

    Pattern-matching


    Начать придётся немного издалека. В Scala есть так называеммые сase classes(естественно и objects тоже). Они объявляются с ключевым словом case, после чего компилятор берёт на себя смелость сделать следующее:
    1. Создать функцию-конструктор с именем, совпадающим с класом.
    2. Имплементировать в классе toString, equals, hashCode на основе аргументов конструктора.
    3. Создать селекторы для всех аргументов конструктора.

    Вся эта магия открывает нам путь к использованию метода match. Давайте взглянем на пример:
    abstract class User

    case class KnownUser(val name: String) extends User

    case class AnonymousUser() extends User

    object Test {
     val users = List(KnownUser("Mark"), AnonymousUser(), KnownUser("Phil"))
     
     def register(user: User): Unit = user match {
       case KnownUser(name) => println("User " + name + " registered")
       case AnonymousUser()     => println("Anonymous user can't be registered")
     }
     
     def main(args: Array[String]) =
      users.foreach( register )
    }

    Итак, общая картина кода: есть абстрактный класс пользователя, есть два его казуальных потомка: известный и анонимный пользователи. Мы хотим зарегистрировать некий список пользователей на (здесь включаем фантазию) встречу. Для чего и используем pattern-matching, который позволяет нам определить разное поведение метода для разных типов объектов и обеспечивает выборку данных из этих объектов.

    После столь жизненного примера можно немного теории о работе метода match. Для каждого выражения case он выполняет проверку на совпадения типа с классом шаблона и соответствия параметров конструктора шаблону. Шаблон в общем случае может включать в себя:
    1. Конструкторы других case-классов. Тут всё вполне рекурсивно, глубина вложенности шаблона ограничивается безумием программиста не ограничивается.
    2. Переменные шаблона. Они становятся доступны в теле функции вычисления результата.
    3. Символы _ обозначающие любое, неинтересующее нас значение.
    4. Литералы языка. Например 1 или "Hello".

    Таким образом мы получаем инструмент, позволяющий описать получение некоторого значения из объекта на основе его структуры (класса) и/или хранимых в нём данных.

    Люди знакомые с базовыми принципами ООП конечно сразу заметят, что проблема эта вполне решается использованием виртуальных функций (более того предлагаемый подход является не лучшей практикой). Однако их использование несёт в себе две трудности: во-первых усложняет поддержку кода при большом числе таких функций (нам ведь захочется регистрировать пользователей и на события, и в группы, и в блоги и т.п., что для каждого случая создавать виртуальный метод?), во-вторых не решает проблемы с тем, что объекты одного типа могут принципиально иметь разную структуру и не иметь возможности предоставлять некоторые данные.

    На вторую проблему хочется обратить особое внимание. Как выглядил бы приведённый выше код в Java? Один класс, если пользователь анонимный выставляем в имени null и проверяем каждый раз (эстеты вроде меня заводят методы типа isAnonymous, состоящие из сравнения поля с тем же null). Проблемы налицо — неявно и небезопасно. Таких примеров великое множество, когда разные вариации структуры объектов объединяются в один класс, а неиспользуемые в конкретном случае забиваются null'ами, или того хуже придумывается значение по умолчанию. Scala позволяет явно описывать вариации структуры объектов, и предоставляет удобный механизм для работы с этими вариациями.

    В заключение, пара мыслей насчёт того, когда данная техника может быть эффективно применена как замена виртуальным функциям:
    • У нас много функций. Да если у нас пара сотен операций, используемых по паре раз, зависящих от структуры и содержания объектов, система на основе case classes — pattern matching будет явно лучше поддерживаема.
    • У нас мало классов. match из пары выриантов всегда хорошо читаем.
    • У нас есть значительные вариации структуры объектов, которые однако надо хранить и обрабатывать единообразно.

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

    Вывод типов


    Думаю, вы уже заметили, что в коде я указывал типы только при объявлении классов и методов. В блоках кода я их практически всегда опускал. Дело в том, что если программист не указывает тип явно, Scala пытается определить его из контекста. Например при инициализации значения константы в определении def s = "Scala" компилятор определит тип константы как строку. Всё это также работает на обобщённых типах, например фрагмент выше val users = List(KnownUser("Mark"), AnonymousUser(), KnownUser("Phil")), создаёт константу типа List[User], автоматически поднимаясь до подходящего уровня в иерархии наследования и используя его для параметризации типа-контейнера. На практике это означает, что можно значительно сэкономить на подобных объявлениях (для развлечения напишите делающий то же самое код на Java или C# :) ).

    Заключение


    Мда… К началу поста уже и скролить долго. Явно пора заканчивать. А сказать хотелось бы ещё про многое: про интереснейший механизм описания обобщённых классов, про неявные преобразования и то, что они на самом деле явные, ленивую инициализацию констант.

    Мне и самому ещё только предстоит изучить модель многопоточности и своеобразный набор примитивов для её реаизации, разобраться с языковой поддержкой xml, поиграться с DSL-строением, посмотреть на их флагманский проект — Lift…

    Однако всё равно осмелюсь сделать пару выводов:
    • Scala является весьма лаконичным и выразительным языком
    • Она предоставляет мощный инструментарий для создания простых и красивых программ

    Вот и всё. Критика приветствуется.
    Напоследок вопрос к массам: интересна ли данная тема, стоит ли писать продолжение?

    UPD: поправил грамматику, спасибо всем оказавшим в этом помощь. Особенно ganqqwerty за массовые разборки с запятыми.

    _________
    All source code was highlighted with Source Code Highlighter.
    Текст подготовлен в ХабраРедакторе
    Поделиться публикацией

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

      +2
      Интересно. Еще хотелось бы узнать, что надо что бы попробовать этот язык. Краткую инструкцию и/или ссылки на рабочие инструкции по установке и настройке нужных программ.
      Кто-то конечно может возразить, что эти инструкции можно и в гугле найти. В ответ я скажу, что и введение в Scala тоже можно найти. Ибо о этом языке наслышан, и хочу на досуге попробовать его (вместе с nemerle). Но раз уж выпал шанс прочитать введение в скалу на Хабре, то хотелось бы и практические шаги тут же сделать.
        +1
        В принципе подходит Eclipse с плагином.
          +2
          Также есть плагин для IntelliJ Idea.
            0
            … Который я бы рекомендовал для ознакомления с языком — при всей моей любви к эклипсу в IDEA плагин гораздо функциональнее.
          +1
          Собственно настройки никакой, у меня из коробки заработал и плагин на Eclipse и интерпретатор. Если имеется в виду установка компилятора и интерпретатора под Windows, к сожалению тут ничего подсказать не могу.
            +1
            Ставим IntelliJ IDEA Comunity edition и Scala плагин, например 0.3.312.
            Или Scala for Netbeans или как уже упоминали Eclipse с плагином.

            Я использовал все три, дольше всего Eclipse, для Netbeans плагин совсем не понравился — сыроват еще, но в последнее время пересел на IDEA. Для тех кому все равно какое IDE использовать посоветовал бы IDEA, но и в Eclipse поддержка Scala вполне достойная.
              0
              в восьмой идее не везьде дополнение кода работает, не знаете как с этим в 9
                0
                В beta было весьма плохо и не только с этим. В релизе говорят, что много чего починили.
                  0
                  надо бы попробывать
                    +1
                    Как много Дюков на хабре развелось.
                  0
                  Субъективно стало лучше, например, по двойному ctrl+space видны недоступные методы. Специфически Scala плагин часто огрубляет дополнение при наличии ошибок. Видимо свой парсер не такой устойчивый/продвинутый как для Java, и пока scalac typer не вычислит все типы, предлагает только методы класса Object.
                    0
                    спасибо, я так понял что изменения мизерные
                  +1
                  Свежескачанная идея community edition и плагин версии 0.3.312 тупо не могут скомпилять проект. LOL как говорится :)
                    0
                    А до этого чем компилировали, если Eclipse, то последний раз когда я его использовал там версия scalac была 2.7.7, в 0.3.312 — 2.8 пререлиз. 2.8 не полностью совместим с 2.7. Ну и пререлиз само собой подразумевает прекачество.

                    Если охота покапаться можно попробовать с командной строки 2.8 скомпилировать. Если неохота, и проект открытый могу и сам покопаться.

                    Ну а вообще YMMV как говорится :),
                      +1
                      Падает компилятор с NoClassDefFound, так-что отличия в исходниках не вариант.

                      Да я и в эклипсе хорошо живу, так минутка выпала попробовал покопаться. Проект я пока не готов публиковать по причине высокой убогости :)
                +2
                В обычном мире pattern matching принято реализовывать через паттерн посетитель, при этом не происходит большого числа функций.
                  +2
                  Во-первых не стоит забывать, что это один из наиболее сложных структурных паттернов.
                  Во-вторых он ориентирован на аккумулирование информации от обхода какой-то структуры, для получения одного значения он неудобен.
                  В-третьих, да, при его использовании такие функции-селекторы концентрируются вместе, но каждый посетитель вынужден определять каждую функцию.
                  +2
                  Пишите еще, было бы интересно почитать. Давно хотелось попробовать, но руки не дошли, так будет гораздо ближе =)
                  И маленький совет — проверяйте орфографию хотя бы вордом, у него многому можно научиться; при этом информация будет восприниматься в разы легче.
                    +2
                    классный пост, спасибо
                      +4
                      Справедливости ради замечу, что в c# сейчас уже есть вывод типов.
                        +3
                        Для generic параметров тоже?
                          +2
                          вот чего не знаю, то не знаю :)
                            +2
                            Тоже. Например, в глубоких вызовах LINQ — там шаблон на шаблоне, и типы нигде не надо указывать.

                            Конкретно этот пример:

                            var list = new List<User>(new AnonymousUser(), new OtherUser(«Vasya»), new SomeOtherUser { Name=«Vasya», Age = 14});

                            Конкретно тут, раз уж вы указываете тип (List), то придётся указать полностью. Но если var list = Repeat(new OtherUser(«Vasya»)), где Repeat: T -> List<T>, тип list будет выведен.

                              +1
                              Хм… Это C# уже и такое понимает? Надо тогда его подучить…
                                0
                                * fix: я тут с выводом немного увлёкся, и забыл про то, какой конструктор у List:

                                List<T>(IEnumerable<T> src);

                                Вот так правильно:

                                var list = new List<User>(new User[] { new AnonymousUser(), new OtherUser(«Vasya»), new SomeOtherUser { Name=«Vasya», Age = 14} });

                                Или, с одним упоминанием типа:

                                var list = new User[] { new AnonymousUser(), new OtherUser(«Vasya»), new SomeOtherUser { Name=«Vasya», Age = 14} }.ToList();
                                  +1
                                  Странно, что вывод generic-параметров для методов работает, а для конструкторов нет.
                                    +1
                                    Да, видимо они посчитали, что конструктор — что-то более ответственное, чем просто вызов метода)
                                  +1
                                  А nemerle умеет и отложенный вывод типов, то есть можно писать так:

                                  def hash = Dictionary();
                                  hash[«key»] = 5;
                                  hash[«another key»] = 9;

                                  а компилятор сам выведет, что у hash тип Dictionary[string,int].

                                  Язык достаточно удобный, из крупных проектов на нем написал uniquation.ru.
                                    +1
                                    Хм… странная фича, не понятно зачем нужна. Неужели у словаря нет удобного конструктора, который, например, пары принимает?
                                      +2
                                      Дело не в конструкторе словаря, а в том, что Nemerle распознаёт тип объекта «hash», анализируя не только строку с его инициализацией, но и код ниже по тексту.
                                      А конструктор может быть или не быть, не о том речь.
                                      +1
                                      прикольный сайт но вот ява апплет как то криво смотрится
                                        0
                                        > Язык достаточно удобный, из крупных проектов на нем написал uniquation.ru.

                                        сам поисковый движок? или и веб-морду тоже?
                                          0
                                          Движок написан на Nemerle, а сам сайт на C# — лень было настраивать Nemerle для ASP.NET для пары страниц.
                                            0
                                            да, вопрос как раз следующий был про то, как прикручивали Nemerle к ASP.NET) но нет, так нет)
                                  +2
                                  Не видел, на работе 2.0 версия языка, а для души не тянет изучать :)
                                    +2
                                    «Для души» nemerle можно, раз .NET знаешь, то будет просто =)
                                      +2
                                      Я дотнетчик так себе. Там студию запустить, да бряк поставить, посмотреть что с Java-сервера пришло =)
                                        +3
                                        Да, тоже сложилось впечатление, что Scala = Nemerle для Java :)

                                        Очень мне понравился Nemerle, жаль что не он на месте F# в 2010 студии. Интересно, что помощнее — Scala или он. Мне кажется, что всё же Nemerle)
                                          –1
                                          Если в Scala нет удобных шаблонов и вообще метапрограммирования, то 100% выиграет Nemerle)
                                            –1
                                            Удобных шаблонов это как?
                                            Метапрограммирования — какого? Кодогенерации врантайме?
                                              +1
                                                –1
                                                То есть имелись в виду макросы? А зачем они в языке с поддержкой функций высокого порядка?
                                                  +1
                                                  Функции высшего порядка — это замечательно, никто не спорит, но все же это run-time сущности. А макросы — compile-time.
                                                  Меня интересует, к примеру, возможно ли на Scala реализовать DSL или АОП.
                                                    +1
                                                    Да.
                                                    Не знаю.
                                                      +1
                                                      Окей, спасибо вам. Значит, здесь все на уровне, и фраза «Scala == Nemerle для Java» себя оправдывает)
                                                      +1
                                                      вот на хабре была уже статья по поводу скалы и ДСЛ
                                                      pleax.habrahabr.ru/blog/39904/
                                                        +1
                                                        DSL — ещё как можно, одно удовольствие :-)

                                                        Вот например. Дядька, кстати, пишет книгу про DSL, в качестве основного языка использует скалу.
                                        +2
                                        Интересно узнать, на какие ограничения автор наткнулся в питоне
                                          +1
                                          Ограничения на размер программ, к сожалению. Языки с динамической типизацией для поддержания работоспособности больших приложений и библиотек требуют неслабой тестовой базы, которая сама является кодом требующим поддержки (рекурсия, ага).
                                            +2
                                            если проблема именно в типах, никто не мешает:
                                            spam = str('eggs')
                                            test = dict({str('spam'): str('eggs'), str('bacon'): str('хабр')}) #unicode in str because py3k can do it!
                                              +2
                                              Не понял примера. В 2.5 str просто делала из объекта строку, 3й я не изучал, но судя по гуглу она делает то-же самое.
                                                +3
                                                Ну а что надо?
                                                Я так понимаю, что запутываешься, где какой тип. А в чем еще проблема с динамической типизацией? Меня вот почему-то устраивает и даже нравится, проще (:
                                                  +2
                                                  Не могу сказать, что сильно путаюсь, но на 100 строк кода хоть один промах с типами да делается. А как выловить такое? Тоьлко тотальным «прозвоном» кода в тестах.
                                          +4
                                          >Python таки хорош, но у нетипизированных языков есть свои ограничения
                                          конкретнее можно?
                                          Вообще-то, Python динамически, но типизированный ;) кури stdtypes.html
                                            +2
                                            См. комментарием выше.
                                            За замечание спасибо, действительно глупость написал.
                                              +2
                                              Парсер съел ссылку, и движок еще не дает мне часто комментировать! И обновляет медленно => не увидел того, что об этом уже спросили.

                                              docs.python.org/library/stdtypes.html
                                                +3
                                                Читал, читал ссылку… Говорюж глупость написал.
                                              +1
                                              мощьный)
                                                +2
                                                Я уже нашёл человека-ворда для проверки, но всё-равно спасибо.
                                                +3
                                                Статья отличная! Буду ждать продолжения! Если честно, тоже хотел свой первый пост написать про Scala в виде «Scala For Dummies») А сравнивать Scala с C# глупо, вернее сравнение будет Scala vs F#.

                                                p.s. Исправьте ошибку «классическим пример высисления суммы»
                                                  +3
                                                  а ещё вернее — Scala с Nemerle ;-)
                                                  +3
                                                  Common Lisp, D и TCL должно хватить для всех неспециализированных задач. Если есть необъяснимая привязанность к jvm [;)], посмотрите Clojure.
                                                    +2
                                                    > Common Lisp
                                                    вы суровы :)
                                                      +4
                                                      Не люблю я лисп, что греха таить. Курс ФП на нём в универе нанёс мне небольшую психическую травму :(
                                                        +1
                                                        Всё, конечно, хорошо…
                                                        Но тут java-программиста приличного днём с огнём не сыщешь. Где ж их на common lisp искать?
                                                          +1
                                                          У D тоже неплохая поддержка ФП и, при этом, отсутствует привязка к платформе jvm. А человек, который смог освоить C++ до состояния «приличного программиста» осилит D за пару дней, в крайнем случае (если кроме C++ ничего в жизни не видел) недель.
                                                            +1
                                                            А к какой платформе у него есть привязка?
                                                              +1
                                                              Вопрос опирается на неверное предположение. :P

                                                              Но на данный момент, безглючные компиляторы есть только для x86 и x86-64.
                                                                +1
                                                                win/linux/solaris?
                                                                  +1
                                                                  да :)
                                                                    +1
                                                                    На самом деле, он сейчас не слишком готов для production. Дайте разработчикам компилятора ещё полтора-два месяца на допиливание.

                                                                    А лучше просто забудьте про D (если нет времени и/или желания посмотреть заранее) и ждите новости на Хабре.
                                                                      +1
                                                                      Вот так оно всегда и получается…
                                                                      С одной стороны «в языке… есть всё что нужно».
                                                                      С другой — компилятор — уже почти готов,
                                                                      профайлера нет (или есть, но глючный, под линух, и с командной строкой)
                                                                      ide по функциональности как turbo pascal 7.0
                                                                      разработчиков на него хрена лысого найдёшь
                                                                      заявленная совместимость совмещается только на сферическом приложении в вакууме
                                                                      и т. д.

                                                                        +2
                                                                        Разработчиков не для языков надо искать, а для задач.
                                                                        А IDE да… под Java они основная компенсация за косяки в языке.
                                                                          0
                                                                          А какие в java ещё косяки кроме, пожалуй, кривых generics и слегка кривоватых примитивных типов?
                                                                            0
                                                                            Это весьма немало. И массивы сделаные так, что их без private final боятся юзать (: И об синхронизацию как она в язык введена мозг сломать можно. И first-class функций не хватает аццки.
                                                                              0
                                                                              Этого немало, только IDE это никак не компенсирует…
                                                                              к сожалению…
                                                                          0
                                                                          > профайлера нет (или есть, но глючный, под линух, и с командной строкой)
                                                                          Во-первых, не глючный, во-вторых, если палец к мыши не прирос, то что плохого в командной строке?

                                                                          > ide по функциональности как turbo pascal 7.0
                                                                          Я бы не сказал, что Descent на уровне TP7. Или TP7 действительно имел outline, подсветку ошибок при редактировании кода и умный автокомплишен?

                                                                          > заявленная совместимость совмещается только на сферическом приложении в вакууме
                                                                          Надо сильно постараться, чтобы написать не кроссплатформенное и не кросскомпайлерное приложение. Не так сильно, как а Java, но всё-равно нужно.

                                                                          Про разработчиков уже сказали выше.
                                                                            0
                                                                            Командная строка — это хорошо. Я её люблю искренне и всей душой за исключением случаев, когда профайлер используется достаточно редко чтобы успеть забыть все команды, но достаточно часто чтобы задолбаться их каждый раз вспоминать.

                                                                            Если говорить, например, про scala plugin for eclipse — первое на что я наткнулся это криво работающая подсветка ошибок и отсутствие organize imports.
                                                                            Rename variable — работает, но глючит.
                                                                            Запуск на исполнение — надо допиливать, прямо «из коробки» не работает.
                                                                              0
                                                                              > Я её люблю искренне и всей душой за исключением случаев, когда профайлер используется достаточно редко чтобы успеть забыть все команды, но достаточно часто чтобы задолбаться их каждый раз вспоминать.

                                                                              Да хоть сейчас. Ключик "-cov" компилятору. :)
                                                                            0
                                                                            Возможно вас заинтересует.
                                                                            www.digitalmars.com/webnews/newsgroups.php?art_group=digitalmars.D.announce&article_id=17369
                                                                            Почта на сайте erdani.com
                                                                0
                                                                И да, Lisp тоже с динамической типизацией ;)
                                                                  0
                                                                  А в TCL всё просто. :) Для разработчика есть всего один тип — строка. Остальные из программы не видны и используются машиной только для оптимизации.

                                                                  Само собой, о HPC на TCL забудьте.
                                                                  0
                                                                  а почему не groovy тогда?
                                                                    0
                                                                    Производительность Clojure не смотрел, но по сравнению с SBCL Groovy — ужасный тормоз.

                                                                    Краткое гугление показало, что у Groovy сложная система метапрограммирования и достаточно сложный синтаксис. Homoiconic (хз как по-русски) языки, например, Clojure, имеют преимущество простого синтаксиа. Функция — форма, принимающая вычисленные один раз аргументы и возвращающая результат. Макрос — форма, которая принимает невычисленные аргументы и возвращает форму, которая, при вычислении, возвращает результат. Вот и вся разница.
                                                                      0
                                                                      >Производительность Clojure не смотрел
                                                                      зря

                                                                      >Краткое гугление показало, что у Groovy сложная система метапрограммирования и достаточно сложный синтаксис.
                                                                      ну вот как минимум на счёт синтаксиса с вами не соглашусь — он может быть вообще максиматьно близким к java
                                                                        0
                                                                        >> Производительность Clojure не смотрел
                                                                        > зря
                                                                        Почему? Сейчас посмотрел. Как и ожидалось, немного медленнее Java, но намного быстрее Groovy(больше двух порядков). Тест числодробительный.

                                                                        > ну вот как минимум на счёт синтаксиса с вами не соглашусь — он может быть вообще максиматьно близким к java
                                                                        Хотите сказать, что у Java простой синтаксис? :D С кучей инфиксных операторов, разделением деклараций и выражений, хитрыми (с точки зрения компилятора, а не математики) правилами по определению порядка вычисления операндов в выражении и т.д.
                                                                  +1
                                                                  А два конструктора можно?
                                                                  Например, Complex(re, im) и Complex(abs, angle).

                                                                  Generics в рантайме доступны?

                                                                  Методы на ходу добавлять можно?

                                                                  При заявленной прозрачности для java-приложений — как там будет reflections работать?
                                                                    +1
                                                                    А как их различать?)
                                                                    Искал тут один товарищ ответ на этот вопрос. Я не совсем понял что именно он нашёл :(
                                                                    Нет. В качестве альтернативы авторы рекоммендуют использовать неявные преобразования типов, про которые я из соображений гуманизма писать не стал.
                                                                    Точно так-же, вся стандартная библиотека Java доступна, вместе с пакетом java.lang.reflect.
                                                                      +1
                                                                      Там не будет глюков при попытке запросить метод с именем «name_=»?
                                                                        +1
                                                                        Нет.
                                                                        scala> class Test { def test_=(s: String) = printf(s)}
                                                                        defined class Test
                                                                        scala> new Test test_= "qq"
                                                                        qq

                                                                          +1
                                                                          Меня, скорее, наоборот интересует:
                                                                          public static void main(...){
                                                                            Method m = Class.forName("Test").getMethod("test_=");
                                                                          }
                                                                          


                                                                            0
                                                                            Экспериментов не ставил. Но проблемы не вижу — формат class-файлов кажется ограничений на имена методов не накладывает.
                                                                              +3
                                                                              scalac когда компилирует занемяет пунктуацию в именах на мнемонику, = на $eq, + на $plus, — на $minus и т.д.

                                                                              Например, если в Scala имеется класс

                                                                              package test
                                                                              
                                                                              class Test {
                                                                                def test_=(s: String) = println(s)
                                                                              }
                                                                              

                                                                              То в Java к test_= методу можно доступится следующим образом:

                                                                              package test;
                                                                              
                                                                              import java.lang.reflect.Method;
                                                                              
                                                                              public class Main {
                                                                              
                                                                                public static void main(String[] args) throws Exception {
                                                                                  Method m = Class.forName("test.Test").getMethod("test_$eq", String.class);
                                                                                  
                                                                                  m.invoke(new Test(), new Object[] {"scala"});
                                                                                }
                                                                              }
                                                                              

                                                                              ну или если reflection не нужен то:

                                                                              package test;
                                                                              
                                                                              public class Main {
                                                                              
                                                                                public static void main(String[] args) throws Exception {
                                                                                  new Test() {
                                                                                    public void callScala(String s) {
                                                                                      test_$eq(s);
                                                                                    }
                                                                                  }.callScala("java");
                                                                                }
                                                                              }
                                                                              
                                                                                +1
                                                                                Интересно. Не знал.
                                                                      +5
                                                                      Очень качественная статья, пешите ещё.
                                                                        0
                                                                        Благодарю, намёк понял.
                                                                          0
                                                                          было бы интересно почитать про то как скала с XML работает, там же вроде на уровне языка
                                                                        0
                                                                        большое спасибо за введение в Scala.

                                                                        очень бы хотелось настоящий примеров из практики, в которых использование Scala сильно облегчает жизнь
                                                                          +1
                                                                          Самый известный — написание на нём бэкэнда Twitter. Второде никто не жаловался :)
                                                                            0
                                                                            про бэкэенд Твиттера мы знаем что он на Scala, а не на Ruby потому что когда его начали писать сам Ruby был довольно хилым и крайне медленным(не то что сейчас ruby1.9, rubinius и т.д.)

                                                                            вот вы написали
                                                                            Причин тому много, основная — всё нарастающее со временем чувство неудобства при работе с cpp-подобными языками. Взгляд мой попеременно падал на Ruby, Groovy, Python, но все они оставляли впечатление инструментов, не совсем подходящих для моего обычного круга рабочих задач (Python-таки хорош, но у нетипизированных языков есть свои ограничения). Scala же, напротив, показалась вполне годным языком.
                                                                            Значит у Вас были задачи, которые императивными языками решались плохо, а на функциональном решались легко и органично. Собственно про эти задачи и хотелось почитать.
                                                                              0
                                                                              Хм… Его вроде делали около года назад, Ruby 1.9 уже был совсем на подходе. Хотя точно истории не знаю.
                                                                              Нет Ruby, Groovy, Python я оценивал не из любви к ФП. Просто в Java есть и моногочисленные косяки и масса неудобств типа отсутствия функциональных типов. Задачи, самые обычные — посмотрите, например на создание списка в моём последнем примере. Во сколько раз делающий то-же самое код на Java длинее?
                                                                              Практики рабочей у меня (надеюсь пока) нет. В качестве упражнения портировал на Scala старый курсовик по ray tracing(где-то 80% готово, всё лень геометрию перенести до конца). В этой задаче пригодилось практически всё, что я описал в посте. Объём кода около 400 строк включая парсер формата сцен. На Java около 2000…
                                                                                0
                                                                                а скорость работы в сравнении в явой?
                                                                                  0
                                                                                  Не замерял, штука в процессе написания.
                                                                                    0
                                                                                    Скорость работы такая же, или быстрее, в случае если не переборщить с ФП и не вляпаться в несколько не очевидных моментов.
                                                                                    1. boxing происходит еще более незаметно, чем в Java. Это происходит в силу того, что примитивные типы теперь дозволено видеть в качестве параметров дженериков.
                                                                                    2. Return использованный внутри анонимных методов или for (что на самом деле тот же анонимный метод). Проблема в этом случае происходит в силу бросания эксепшина NonLocalReturnException (с названием могу и напутать), что происходит довольно долго (а на деле скажем этот код совсем простой и должен был в итоге выполниться в три раза быстрее).
                                                                                    3. ФП позволяет сократить количество кода, но за счет скорости выполнения. Скажем иногда удобно много раз итерироваться по массиву выполняя вещи, которые можно было сделать в одну итерацию. Происходит подобное просто из-за удобств функционального стиля.
                                                                            0
                                                                            Сравниваю вышенаписанное с C#. Я не вижу чем скала в примерах удобней C#, а даже наоборот — более запутанный и неоднозначный синтаксис.

                                                                            На счет коллекций, начиная с C# 3.0 (2004 г) коллекции инициализируются так:
                                                                            var list1 = new List { new User(«Masha»), new User(«Petya»), kolyaUserObject };
                                                                            и так
                                                                            var list2 = new [] { «string1», «string2» };

                                                                            В версиязх 4,5,6 огромное кол-во плюшек добавлено.Например именованные и необязательные аргументы в методах. Значения по умолчанию для геттеров:

                                                                            string Field1 {
                                                                            get; = «default value»
                                                                            set;
                                                                            }

                                                                            Pattern Matching правда вот совсем недавно появился в 7 версии.

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

                                                                            Самое читаемое