воскресенье, 9 октября 2011 г.

Впечатления от Clojure

Пришлось мне столкнуться по-службе с Clojure. Мои впечатления от знакомства:
  1. Первое, что бросается в глаза — это дурацкие [] и {} вместо расово верных (). Не скажу, что они упрощают чтение кода, ИМХО разница невелика. А вот написание усложняют (по крайней мере мне). Набирать закрывающие сущее мучение; вылазит вот такое ))}))]) безобразие и сиди считай скобки. Так недалеко и до JavaScript с его вечными });});});
  2. Зато, эти же самые [] и {} позволяют сделать конфиг с симпатичным синтаксисом почти-JSON.
    {
      :listen {
        :host "localhost"
        :port 8080
      }
      :db {
        :host "localhost"
        :port 5432
        :database "database"
        :user "root"
        :password "secret"
      }
    }
  3. Жутко неудобно писать императивный код. Мутабельность здесь не любят. Код, конечно, от этого становится чище, но времени на написание уходит чуть больше.
  4. Нет многострочных комментариев. Пришлось написать reader macro, добавляющий комментарии в стиле Common Lisp.
    (defn dispatch-reader-macro [ch fun]
      (let [dm (.get (doto
                       (.getDeclaredField clojure.lang.LispReader
                                          "dispatchMacros")
                       (.setAccessible true))
                     nil)]
        (aset dm (int ch) fun)))

    (defn read-comment [rdr pipe]
      (loop [s nil]
        (let [c (.read rdr)]
          (if-not (and s (= c (int \#)))
                  (recur (= c pipe))))))

    (dispatch-reader-macro \| read-comment)
    Единственное неудобство: нужно делать require во всех файлах, где эти комментарии используются.
  5. Очень понравился Leiningen. Собрать с его помощью jar-файл и запустить его на сервере оказалось очень просто. Сделано "для людей".

пятница, 1 апреля 2011 г.

GtkFileChooser и Win32

Вчера всплыла интересная проблема. File-chooser в CL-GTK2 не правильно работает с не-ASCII именами файлов.

Оказалось, что win32-версия GTK+ определяет два набора функций:
  • первый содержит те-же функции, что и unix-версия, но работающие с локальной кодировкой (а не utf8);
  • второй набор работает с utf8, но все функции имеют суффикс _utf8.
Самое интересное то, что файл gtkfilechooser.h с помощью препроцессора переименовывает функции из второго набора и скрывает из первого. DLL же экспортирует оба набора и CL-GTK2 как ни в чём ни бывало использует первый, неправильный набор.

Оказалось, что не все функции легко исправить потому, что они генерировались отдельным скриптом. Трудность заключалась в том, что нужно было генерировать reader macros. Символы #+win32 упорно не желали печататься как следует. Получалась никуда не годная ерунда вроде такой: |#+WIN32|

После долгих мучений родился такой workaround:

(defclass print-readtime-condition ()
  ((condition :initarg :condition)))

(defmethod print-object ((o print-readtime-condition) stream)
  (format stream "#~A" (slot-value o 'condition)))

Теперь макрос-генератор может выводить условия так:

(make-instance 'print-readtime-condition :condition :+win32)


Результаты ночных бдений: https://github.com/andy128k/cl-gtk2