Слегка разочаровался в Scala

Когда-то, довольно давно, я взялся за поиск альтернативы для C++, который во все времена был и, как мне думается на данный момент, будет моим основным рабочим инструментом. Само собой, эта альтернатива мне была нужна не для того, что бы перейти в какую-то иную сферу, а для тех случаев, когда либо хочется написать что-то свое, либо нужно быстро создать какой-то прототип, проверить ту или иную концепцию. В такой ситуации JVM-based язык очень удобен и, по большому счету, безальтернативен, конкуренцию может составить разве что Python со своим простым синтаксисом и безграничным набором библиотек. Continue reading

MemCardsBuilder готов

Завершил работу над экспериментом по написанию кода на Scala и знакомством с библиотекой LuceneMorphology – проектиком MemCardsBuilder. Дабы не тратить время совсем уж впустую, я старался сделать эксперимент максимально полезным при минимальном функционале. Поэтому, функций не так уж и много:

  1. Анализ заданных текстов и выявление частот вхождения слов с учетом морфологии. Благодаря учету морфологии see, saw, seen расцениваются как одно слово, а не 3.
  2. Загрузка переводов с lingvo.yandex.ru для полученного словаря.
  3. Построение ментальных карт в формате разделения при помощи табуляций. Данный формат воспринимает такое замечательное приложение как Anki. При импорте карт в Anki, необходимо выставить галочку “Allow HTML in fields”.

На данный момент, да и скорей всего не только на данный момент, приложение поддерживает только en -> ru построение карт. В принципе, библиотека LuceneMorphology позволяет организовать ru -> en построение без особых проблем и в MemCardsBuilder заложена такая возможность, просто она не реализована. А вот для организации поддержки чего-то за пределами русский<->английский я не вижу возможностей, т.к. я не нашел какой-то аналогичной библиотеки поддерживающий морфологический анализ для, например, испанского или немецкого языков.

Пример того, как можно запустить приложение:

java -jar MemCardsBuilder-1.0-SNAPSHOT-jar-with-dependencies.jar --from-pos 100 --to-pos 110  -s /path/to/analysed/file/data.txt -d ~/out.txt

Приложение понимает следующие ключи:

  • –from-pos (не обязательный параметр, по умолчанию равен 0) минимальный индекс обрабатываемого слова. Например, был построен словарь из 1000 слов, при задании ключа –from-pos 100, все слова с индексом от 0 до 99 не войдут в результирующую выборку.
  • –to-pos (не обязательный параметр, по умолчанию равен количеству слов) максимальный индекс обрабатываемого слова.
  • –meanings-count (не обязательный параметр, по умолчанию равен 2) максимальное количество значений слова, для каждой из частей речи, включаемых в ментальную карту.
  • -s (обязательный параметр) файл с данными для анализа. Ключ -s может быть использован несколько раз в этом случае все указанные файлы будут обработаны как единый объект.
  • -d (обязательный параметр) файл для записи ментальных карт.

Собранное приложение можно загрузить в двух форматах:

  1. Все в одном флаконе: MemCardsBuilder-1.0-SNAPSHOT-jar-with-dependencies.jar
  2. Только сам проект: MemCardsBuilder-1.0-SNAPSHOT.jar

Неявное преобразование к перечислениям

Захотелось мне ужасного: сделать неявное преобразование из строки к перечислению в Scala. Почему ужасного? Да потому что чем больше неявных преобразований в реальном, большом проекте, тем тяжелее понять что же происходит на самом деле без отладчика. А отладчик, мало того что доступен далеко не всегда и если есть возможность обойтись без него, то она явно предпочтительнее. Но это все философия, далеко не все будут с ней согласны.

Есть список частей речи в виде перечисления. При парсинге, части речи приходят в виде строки и должн быть преобразованы к перечислению, например “сущ.” -> Acronym.noun.

Continue reading

Поговорим об акторах

Лично мне очень нравится концепция акторов. Что интересно, познакомился я с ней куда раньше повальной моды на функциональщину, в году так 2003, когда начал плотно работать с библиотекой ACE (это та, которая The ADAPTIVE Communication Environment). Ну а сейчас акторами никого не удивишь, все про них только и говорят. И это хорошо, так как данная модель сильно упрощает отладку и разработку, при относительно не большой просадке по производительности и памяти.

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

Как получить индекс в цикле for

Периодически Scala сильно удивляет как в хорошем смысле этого слова, так и в плохом. С циклом for вышло именно так. Из плохого мной было обнаруженно то, что получить доступ из вне цикла к счеткику никак не выйдет. Поясню на примере C++ о чем идет речь:

int index;
for(index = 0; index < ....) {...}
std::cout << index; // и тут мы получили количество итераций

Да, обломс… Единственный найденный мной рабочий вариант выглядит следующим образом, что на мой взгляд очень и очень печально:

val strings = List("one", "two", "three", "four")
var index = 0
while (index < strings.length) {
  index += 1
}

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

val strings = List("one", "two", "three", "four")

for ((string, index) <- strings.zipWithIndex) {
  println("Index: " + index + ", string: " + string)
}

var VS val

В Scala существуют два типа переменных, константные и изменяемые. На фоне большинства мэйнстрим языков, подход выглядит довольно странно: константные “переменные” декларируются посредства ключевого слова val, для создания изменяемых переменных используется ключевое слово var.

Столкнувшись с таким подходом, первый заинтересовавший меня вопрос был “есть ли какая-то разница на уровне JVM в var и val?”. Возьмем простейший пример:

    val str1 : String = "String1";
    var str2 : String = "String2";

Что будет скомпилированно в:

   0:   ldc #23; //String String1
   2:   astore_2
   3:   ldc #25; //String String2
   5:   astore_3

Итого: как и ожидалось, никакой разницы нет, просто проверка на этапе компиляции.

И еще пара моментов. Параметр функции всегда константа:

  def fn(arg : String) {
//    arg = "Test"; // error: reassignment to val
  }

В отличие от параметров конструктора, которые могут быть как константными, так и изменяемыми переменными. Для получения изменяемого параметра, необходимо явно это указать при помощи var.

class TestClass(v1 : String,  var v2 : String) {
//  v1 = "NewVal" // error: reassignment to val
  v2 = "NewVal"
}

На мой взгляд, поход довольно запутанный и не очень удобный, различать константа/не константа по одной букве довольно затруднительно. Но, что есть – то есть.

В поисках альтернатив C++

В связи со своим вынужденным переходом в разработчики Java я получил довольно интересную возможность посмотреть на C и C++ со стороны. В целом, мне нравится то что я вижу глядя на C++ с позиции Java разработчика, но, само собой, нашлось одно «но», которое, если быть честным, мне и раньше не давало покоя: C++ совершенно не подходит для быстрого прототипирования. По большому счету это единственный недостаток который я отмечаю на данный момент.

Если говорить про Java, то с быстрым прототипированием тут все нормально, в то время как скорость разработки приложений приблизительно такая же•• как и в случае с C++, ну может на 10% быстрее. При этом язык крайне ограниченный, практически до убогости, что после 10 лет разработки на C++ вызывает довольно ощутимое отторжение.

Понимая, что так дело не пойдет, я взялся за поиск приличной альтернативы C++. Изначально подумывал про Erlang, ведь в основном я пишу что-то сетевое, но в итоге от этого варианта решил отказаться, потому как за пределами сетей Erlang мягко говоря бесполезен, а в самих сетях, зачастую, ограничен в плане набора доступных библиотек. В результате довольно долгих поисков выбор остановился на JVM, ведь JVM — это действительно кроссплатформенное решение (в отличие от того же CLR) с большой базой библиотек под нормальными лицензиями (MIT, BSD и, в худшем случае, LGPL). Плюс, в JDK, начиная с 7-й версии, появилась поддержка асинхронного ввода/вывода, т.е. возникла вполне реальная возможность писать не тормозящие где попало сетевые приложения.

К основным языкам базирующимся на JVM, само собой за исключением самой Java, относятся Clojure, Groovy и Scala. Clojure — Lisp-подобный язык, так что отмел его сразу. Да, я к Lisp отношусь хорошо, но вот куча народу вокруг — нет, так что никакой возможности реально использовать что-то Lisp-подобное я не вижу. Groovy — хороший язык, но без чего-то действительно цепляющего. А вот Scala… Да, Scala — это язык с довольно крутой кривой вхождения, при этом богатым синтаксисом и отличными возможностями.

У всех разные способы оценить пригодность языка для своих нужд. Кто-то первым делом реализует быструю сортировку, кто-то пишет Hello World. А я, обычно, пишу Echo-сервер с клиентом. Continue reading