*** ВНИМАНИЕ: Блог переехал на другой адрес - demin.ws ***

понедельник, 6 февраля 2012 г.

Born by copy-paste

I usually start crying when see a copy-paste with numbered variables. A probability to screw up is very high, just forget to change a single number after pasting. Here is a horrifying piece of code (don't you mind to spot on an incy wincy typo?)

void Test_SplitPair() {
  typedef std::pair<std::string, std::string> Pair;
  using string::SplitPair;

  const Pair p1 = SplitPair("", '=');
  assert(p1.first.empty());
  assert(p1.second.empty());

  const Pair p2 = SplitPair("=", '=');
  assert(p2.first.empty());
  assert(p2.second.empty());

  const Pair p3 = SplitPair("name=value", '=');
  assert(p3.first == "name");
  assert(p3.second == "value");

  const Pair p4 = SplitPair("name = value", '=');
  assert(p3.first == "name");
  assert(p3.second == "value");

  const Pair p5 = SplitPair(" n ame  \t =  va lue  \r\n", '=');
  assert(p5.first == " n ame  \t ");
  assert(p5.second == "  va lue  \r\n");
}

Any ways to make to better? The ideal solution is to split to multiple tests. But even less radical approach works to avoid copy-paste problems:

void Test_SplitPair() {
  typedef std::pair<std::string, std::string> Pair;
  using string::SplitPair;
  {
  const Pair p = SplitPair("", '=');
  assert(p.first.empty());
  assert(p.second.empty());
  }
  {
  const Pair p = SplitPair("=", '=');
  assert(p.first.empty());
  assert(p.second.empty());
  }
  {
  const Pair p = SplitPair("name=value", '=');
  assert(p.first == "name");
  assert(p.second == "value");
  }
  {
  const Pair p = SplitPair("name = value", '=');
  assert(p.first == "name");
  assert(p.second == "value");
  }
  {
  const Pair p = SplitPair(" n ame  \t =  va lue  \r\n", '=');
  assert(p.first == " n ame  \t ");
  assert(p.second == "  va lue  \r\n");
  }
}

Рожденный копипастом

Всем своими фибрами ненавижу копипаст с участием переменных с номерами. При очередном копипасте вероятность забыть исправить одну циферку крайне велика. Например, ужасный кусок кода (не правда ли, просто найти опечатку?):

void Test_SplitPair() {
  typedef std::pair<std::string, std::string> Pair;
  using string::SplitPair;

  const Pair p1 = SplitPair("", '=');
  assert(p1.first.empty());
  assert(p1.second.empty());

  const Pair p2 = SplitPair("=", '=');
  assert(p2.first.empty());
  assert(p2.second.empty());

  const Pair p3 = SplitPair("name=value", '=');
  assert(p3.first == "name");
  assert(p3.second == "value");

  const Pair p4 = SplitPair("name = value", '=');
  assert(p3.first == "name");
  assert(p3.second == "value");

  const Pair p5 = SplitPair(" n ame  \t =  va lue  \r\n", '=');
  assert(p5.first == " n ame  \t ");
  assert(p5.second == "  va lue  \r\n");
}

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

void Test_SplitPair() {
  typedef std::pair<std::string, std::string> Pair;
  using string::SplitPair;
  {
  const Pair p = SplitPair("", '=');
  assert(p.first.empty());
  assert(p.second.empty());
  }
  {
  const Pair p = SplitPair("=", '=');
  assert(p.first.empty());
  assert(p.second.empty());
  }
  {
  const Pair p = SplitPair("name=value", '=');
  assert(p.first == "name");
  assert(p.second == "value");
  }
  {
  const Pair p = SplitPair("name = value", '=');
  assert(p.first == "name");
  assert(p.second == "value");
  }
  {
  const Pair p = SplitPair(" n ame  \t =  va lue  \r\n", '=');
  assert(p.first == " n ame  \t ");
  assert(p.second == "  va lue  \r\n");
  }
}

четверг, 2 февраля 2012 г.

Вiased review of "Seven languages in seven weeks"

I have finished accelerated reading of "Seven languages in seven weeks" by Bruce Tate.

http://demin.ws/images/covers/english/7-languages-in-7-weeks-cover.jpg

In my case it was "Seven languages in seven evenings". For each language there is an introduction, which makes sense only if a language is brand new for you. There are also interviews with creators of the languages. One of the asked interesting questions was about what the author would like to change in the language if he could re-design it from scratch now.

Languages:
  • Ruby
  • Io
  • Prolog
  • Scala
  • Erlang
  • Clojure
  • Haskell
The reviews of each chapter below are my subjective views two things at once: a programming language and a material about it. Why? For familiar languages it hardly makes any sense to describe the language per se, but to note interesting distinctive features could be useful. But if a languages is a green field, it is worth describe it in general.

Ruby

The Ruby chapter was quite useless for me because I thoughtfully read "Programming Ruby 1.9", and have been hooked. Ruby is an amazing scripting language. Each time when programming in Ruby I feel so delighted similar to when I tried PHP first time after Perl.

Ruby's creator, Yukihiro Matsumoto, says in the interview, that if he could re-design Ruby today, he'd like to change the concept of multi-threading to "Actor".

In short, "Actor" is when concurrent threads don't share memory and don't use mutex or semaphores for synchronization. Instead, they send and receive messages to each other, and messaging is provided by runtime and built-in to the languages syntax. Examples: Scala, Go, Erlang, Io.

Io

Io is a very small, compact language, based on prototypes like JavaScript, where there is no distinction between classes and objects.

There is an interesting concurrency feature in addition to actors and coroutines (cooperative multi-threading as in Lua), called futures. "Futures" are similar to the actor. There the only difference is when the caller thread tries to use the result of the future, it will be blocked until the future completes and gives the result back.

An example from the book:

// Fire up the future.
futureResult := URL with("http://google.com/") @fetch
writeln("Continue immediately when future is running in background.")
// This line will be executed immediately after spawning the future.
writeln("fetched ", futureResult size, " bytes")
// But this line will be blocked until the future returns.

Prolog

I've been gnawing this animal for years. But thanks to Erlang recently, all this functional stuff in general is now giving up for me, and monsters like Prolog or Haskell don't look so scary anymore.

It turned out that the depth of the material about Prolog has matched precisely with my level. The eight queens problem and a Sudoku solver were excellent examples for me.

Shortly, a program in Prolog is a pile of facts and rules. Then the Prolog runtime performs a depth-first search amongst possible results and tries to find those satisfying all the given facts and rules.

In fact, the Sudoku solver program is a set of variables, representing the Sudoku field, and a list of rules (summations by columns, rows and squared groups) according to the rules of Sudoku. Then Prolog performs an exhaustive search to find the values and their combinations satisfying the rules.

Of course, this is very much a superficial glance, but this has given me much more understanding of Prolog.

Scala

I will note only a few facts interesting to me.

Multi-threading is based on actors. After Erlang and Go you understand how good and handy it is. I think that Scala has all possible bells and whistles even invented for programming languages. But sometimes it has not only good consequences.

Erlang

I'm a big fan of Erlang and already read a few big books. That's why this book hasn't given to me anything new. But for novices this introduction may give quite solid view on Erlang functional approach and concurrency model.

Clojure

Clojure is a Lisp-based language driven by Java VM.

It has an interesting feature called STM, software transactional memory. In STM a piece of code is declared to be a transaction. It is executed atomically or all the changes of variables are rolled back.

And finally, Haskell

Haskell is a taught guy. The introduction in this book is very light and minimal, just to remember the word "Haskell". I read "Programming in Haskell" and currently I'm on "Real World Haskell", that's why I simply skimmed the chapter in this book.

Okay, to sum up. This book is to be read just once, to broaden your outlook.

Предвзятое мнение о книге "Seven languages in seven weeks"

Закончил ускоренное чтение по диагонали книги "Seven languages in seven weeks", автор Bruce Tate.

http://demin.ws/images/covers/english/7-languages-in-7-weeks-cover.jpg

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

Описываются языки:
  • Ruby
  • Io
  • Prolog
  • Scala
  • Erlang
  • Clojure
  • Haskell
Обзор каждой главы - это мой субъективный взгляд на две вещи сразу: язык программирования и материал главы про него. Объясню почему - для знакомых языков вряд ли имеет смысл описывать сам язык. Может имеет смысл отметить интересные отличительные моменты. А вроде для неизученных, типа Пролога или Clojure, можно и остановиться немного на самом языке.

Ruby

Про Ruby ничего особенно из книги не вынес, так как вдумчиво читал "Programming Ruby 1.9", после чего подсел на этот язык. Ruby - фантастический скриптовой язык. Каждый раз, когда пишу на нем, испытываю удовольствие примерно такое, когда я после Perl'а попробовал в первый раз PHP.

Автор языка сказал в интервью, что, создавая бы язык заново сегодня, он бы хотел для многопоточности вместо традиционных потоков сделать модель "actor".

В двух словах, Actor - это когда параллельные потоки разделяют ресурсы не через память и механизмы синхронизации типа мьютексов и семафоров, а через обмен сообщениями, прием и посылка которых обеспечиваются средой, и они встроены в синтаксис языка. Например, как в Scala, Go, Erlang, Io.

Io

Io очень компактный, на мой взгляд эзотерический язык, основанный на прототипах, как JavaScript, когда нет четкого разделения между классами и объектами. Минимальный и очень простой синтаксис.

Интересный механизм многопоточности в дополнение к actor и coroutine (коллективная многозадачность, как в Lua), называемый futures. "Futures" - это вроде бы как обычный actor, поток запущенный работать параллельно. Но с одним отличием: как только создающий поток попытается воспользоваться результатом future, он будет заблокирован до тех пор, пока future не вычислит это значение.

Примерчик из книги:

// Запускаем future
futureResult := URL with("http://google.com/") @fetch
writeln("Сразу начинаем делать что еще, пока future работает в фоне.")
// Эта строка будет выполнена сразу.
writeln("fetched ", futureResult size, " bytes")
// А вот эта строка будет заблокирована, пока future не выполнится.

Идем дальше, Prolog.

Этого зверя я грызу давно. К счастью, благодаря освоению Erlang'а, я стал реально въезжать в функциональную тему в целом, и монстры типа Пролога или Хаскелла уже не за пределами понимания.

Так совпало, что глубина материала по Прологу легла точно для моего уровня. Задача восьми ферзей и поиска решений Судоку были для меня отличными примерами.

В двух словах: программа для Прологе - это набор фактов и связей между ними. Затем Пролог, выполняя программу, поиском в глубину обходит пространство решений и выбирает те, которые удовлетворяют всем заданным фактам и связям между ними.

Фактические программа поиска решения Судоку - это набор переменных, составляющих клетки поля Судоку, и набор правил - разнообразные суммирования по группам, по строками и столбцам (по правилам Судоку). И затем Пролог перебором ищет подходящие значения и комбинации переменных.

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

Идем дальше, Scala.

Отмечу только отдельные факты, интересные мне.

Многопоточность на основе actors, то есть когда потоки обмениваются сообщениями. После Go и Erlang понимаешь как это удобно и правильно.

Про остальное - по-моему в Scalа есть все возможные свистелки и перделки, когда-либо придуманные в области языков программирования. В общем, если вы фанат Java VM, то надо брать полноценную книгу по Scala и грызть ее.

Идем далее, Erlang.

Тут тоже скажу мало, так как я фанат этого языка, и уровень этой книги мне был мал, но введение дается хорошее для ознакомления с функциональной сутью Erlang'а и его моделью многопоточности.

Clojure

Снова язык на основе Java VM. Clojure - это разновидность Лиспа со всеми вытекающими.
Интересная возможность языка, в общем-то не связанная с его лисповой сущностью - это STM, software transactional memory. Это когда некий кусок кода в программе объявляется транзакцией, и он выполняется атомарно, либо все изменения откатываются.

Ну и под занавес, Haskell.

Хаскелл суров, и данная книга - это крайне минимальное введение, просто для запоминания слова Хаскелл. Я кое как осилил отличную книгу Душкина и "Programming in Haskell", а сейчас читаю "Real World Haskell", поэтому главу этой книги просто пролистал.

Вывод: книга 100% одноразовая, но, как говориться, раз не... полезно для кругозора и для программистских терок на кухне.