← All posts tagged code

lovesan

Немного легкой утренней наркомании.

public static void CallWithEscapeContinuation(Action<Action> f)
{
  var escapeTag = new Exception();
  Action escapeProcedure = () => { throw escapeTag; };
  try
  {
    f(escapeProcedure);
  }
  catch (Exception e)
  {
    if (ReferenceEquals(escapeTag, e)) return;
    throw;
  }
}

lovesan

В свободное время пилю свой лисп, кросс-интерпретатор на C#.
Придумал новый подход к рантайму, который заключается в забивании на наследование и прочее ООП.

Скоро наверное выложу на гитхаб в SLXI или куда еще

Примерчик для затравки:

// (write-line
//     (reduce (lambda (x y) (concatenate 'string x y))
//             (list "Hello, " "World!")
//             :initial-value ""))
Console.WriteLine(
    LispObject.CreateList(LispObject.CreateString("Hello, "), LispObject.CreateString("World!"))
    .AsEnumerable()
    .Aggregate(LispObject.CreateString(""), (acc, x) => acc.AppendToString(x))
    .StringValue);

[ colorized: http://pastebin.com/t09kDckY ]

lovesan

Дико крутая библиотека:
https://github.com/AutoMapper/AutoMapper

Вот скринкаст по теме:
http://dnrtv.com/dnrtvplayer/player.aspx?ShowNum=0155

Короче, суть в автоматизированном отображении ADO(модель БД, whatever) на DTO(ViewModel, объекты, удобные для вьюх).

Мы просто берем, где-то на старте приложения пишем Mapper.CreateMap<SourceType, DestType>(), а потом в экшнах контроллера пишем Mapper.Map(sourceObject, destObject) и библиотека нам генерирует одни объекты из других автоматически, на основе имен свойств и методов, например. Более того, библиотека даже поддерживает flattening, т.е. может из вложенных ADO автоматически сделать плоские DTO.

Это само по себе круто, но можно сделать еще удобнее, прикрутив к методам контроллера аттрибуты:
http://lostechies.com/jimmybogard/2009/06/30/how-we-do-mvc-view-models/

Вот пример. Допустим у нас есть некоторый класс, отображение таблицы БД.

class User
{
  public string Name { get; set; } 
  public string Surname { get; set; } 
  public string GetFullName() { return Name + " " + Surname; }
}

И DTO для отображения.

class UserDto
{
  string FullName { get; set; } 
}

Где-то в global.asax мы настроили отображение:

Mapper.CreateMap<User, UserDto>();

А в контроллере его используем:

class UserController : Controller
{
  [AutoMap(typeof(IEnumerable<User>), typeof(IEnumerable<UserDto>))]
  public ActionResult List()
  {
    return View(DB.Users.AsEnumerable());
  }
}

Ну и во вьюхе например такое:

@model IEnumerable<EgoistPortal.Models.UserDto>

@foreach(var u in Model)
{  
  <div>@u.FullName</div>
}

----------------------------------

Есть ли в рубях что-нибудь подобное, например?

lovesan

Верстальщики в зале есть?
Суть такова:

Есть такая страница:
<body>
<div id="topBanner">...</div>
<div id="top">...</div>
<div id="content">...</div>
</body>

В top и content в бэкграунде висит две части текстуры, причем плотно подогнанные друг под друга. Т.е. в top - шапочка текстуры, в content - повторяющаяся по вертикали часть, которая сверху сочетается с низом текстуры из top.
И top и content на странице отцентрированы(width: Npx; margin: 0 auto;).
Нужно сделать так, чтобы content растягивался как минимум до низу страницы, т.е. чтобы от шапки до низу была текстура из content, даже если внутри content пусто. Текстура, кстати, прокручивается с контентом, если он есть.

Можно ли сделать оную задачу на чистом CSS 2.1 и XHTML 1.0?
Я пока что придумал изъебство на JS:
<div id="content">
...
<script type="text/javascript">setContentMinHeight();</script>
</div>


Сама функция setContentMinHeight такая:

function setContentMinHeight() {
  var b = document.getElementById("topBanner");
  var t = document.getElementById("top");
  var c = document.getElementById("content");
  if(t && c)
  {
    var mh = window.innerHeight
             - t.offsetHeight
             - ( b ? b.offsetHeight : 0);
    mh = (mh > 0 ) ? mh : 0;
    c.style.minHeight = mh + "px";
  }
}

window.onresize = setContentMinHeight;

lovesan

Кстати, какой у вас coding standard для сишечки?

Я например дико котирую такой вот, и использую везде где можно:
( пример отсюда: http://en.wikipedia.org/wiki/GNU_coding_standards#Code_formatting )

INT main(INT argCount, CHAR *args[])
{
    ERROR_CODE err = ERROR_NO_ERROR;
    INT returnCode = 0;
    GIZMO foo = {0};
    err = GetGizmo(&foo, args[1]);
    if(ERROR_FAILURE(err)) goto displayError;
check:
    if(GIZMO_MOOMIN == foo.type)
        DisplayMessage("It's a moomin.");
    else if(foo.bar < (GIZMO_SNUFKIN_THRESHOLD / 2)
            || (0 == StringCompare(foo.className, "snufkin")
                && foo.bar < GIZMO_SNUFKIN_THRESHOLD))
        DisplayMessage("It's a snufkin.");
    else
    {
        CHAR *barney; // Pointer to the first character after
                      //   the last slash in the file name.
        INT wilma; // Approximate size of the universe.
        INT fred;  // Max value of the `bar' field.
        do
        {
            err = GizmoFrobnicate(
                      &foo,
                      GIZMO_SNUFKIN_THRESHOLD,
                      &barney,
                      &wilma,
                      &fred);
            if(ERROR_FAILURE(err)) goto displayError;
            err = GizmoTwiddle(
                      &foo,
                      barney,
                      wilma + fred);
            if(ERROR_FAILURE(err)) goto displayError;
        } while(foo.bar >= GIZMO_SNUFKIN_THRESHOLD);
        if(ERROR_FAILURE(err)) goto displayError;
        err = GizmoStoreSize(&foo, wilma);
        goto check;
    }
cleanup:
    CleanGizmo(&foo);
    return returnCode;
displayError:
    DisplayError(err);
    returnCode = 1;
    goto cleanup;
}

lovesan

Система "залезть в интернет с файрфокса". Из конечных приложений - минимум Xfce4, лиса с флешем, emacs, sbcl, vim/gvim.

equery s '*' | sed -e 's/.*size(\(.*\))/\1/g' | awk '{s+=$0} END {print s}'

==> 2265127942

2 265 127 942!!

И вот это, бля, одна из таких вещей, из-за которых я говорю, что что-то, бля, в этих ваших прыщах сильно-сильно нет так.

lovesan

Уже день ебусь с лексером s-выражений. Выходит охуительная простыня из goto, в которой я уже начинаю путаться.

Ненавижу лексеры! (Люблю, кстати, PEG, но PEG тормозят и жрут кучу памяти.)

Серьезно, самое сложное в парсинге(включая собственно парсинг s-выражений внутри компилятора) любого более-менее современного лиспа это лексер. Даже если используется алгоритм считывателя, как в CL, и синтаксис изменяемый, все-равно, символы, и главное, числа требуют лексера.
Вот примерная грамматика токенов микролиспа(правда в нем '#' к токенам не относится, это диспатч-литера ридера, как и в CL, но все-равно) и тех s-выражений, реализацию которых пишу на C#.


numberN -> radixR ws complexR  ;; 'R' означает что
                               ;; правило дублируется для всех систем
                               ;; счисления от 2 до 36 включительно
complexR -> realR
            | realR '@' realR
            | realR sign urealR [iI]
            | realR sign [iI]
            | sign urealR [iI]
            | sign [iI]
realR -> sign urealR
urealR -> uintR
          | uintR '/' unintR
          | decimal ;; цифры у чисел с плавающей точкой - только в 10чной с.с.
decimal -> digit10+ expt
           | digit10+ '.' digit10* expt?
           | digit10* '.' digit10+ expt?
           | digit10* '.' expt
uintR -> digitR+
radix2 -> '#b' | '#B'
radix8 -> '#o' | '#O'
radix10 -> ('#d'|'#D')?
radix16 -> '#x' | '#X'
radixR -> '#' baseR 'r'
digit2 -> [0-1]
digit8 -> [0-7]
digit10 -> [0-9]
digit16 -> [0-9A-Fa-f]
digitR -> < Цифра берется из множества десятичных
            цифр с добавлением латинского алфавита до Z(== 35),
            соответственно системе счисления.
            Без учета регистра. >
baseR -> < число от 2 до 36 в десятичной с.с. >
ws -> [ \t\r\n]*

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

У символов грамматика примерно такая(написал криво, но суть понятна, думаю):
symbol -> keyword | uninterned | ordinary
keyword -> packageMarker (escape | char)+
uninterned -> '#:' (escape | char)+
ordinary -> ((escape | char) (packageMarker (escape | char))?)+
packageMarker -> ':' | '::'
escape -> singleEscape | multiEscape
singleEscape -> '\\' 'u' digit16 digit16 digit16 digit16
                | '\\' [^u]
multiEscape -> '|' (singleEscape | [^|] )* '|'
char -> [^:]


Понятное дело, что строить для этого дела правильный DFA(особенно вручную) каким-нибудь lex это просто пиздец - у него выйдет громадная таблица, которая еще не факт что правильная(грамматики выше заданы довольно неформально, на самом деле там куча деталей), ну и вообще, нам же надо это все парсить, а не только распознавать.

Поэтому такую штуку приходится парсить ручками, лапшой из goto и ad-hoc костылей на тыщу строк кода. Неприятно, но а что делать.

Но это кстати довольно обычная ситуация в деле написания парсеров.
Я имею ввиду, что бы там не писали в т.н. "Dragon Book", и прочей подобной литературе - на самом деле, 99% real-world компиляторов используют именно самописные парсеры и лексеры с кучей ad-hoc костылей и подпорок. Ну если языки не совсем игрушечные, конечно.

lovesan

(defparameter *fact-vm*
    (make-vm (list (cons '* #'*)
                   (cons '- #'-)
                   (cons '< #'<)                   
                   (cons 'in #'read)
                   (cons 'cls #'clear-input)
                   (cons 'out #'print))
      '((:op :init-stack)
        (:op cls)
        (:mov n (:op in))
        (:mov ret (:label end))
        fact
        (:test (:op < (:reg n) (:const 2)))
        (:jc (:label ret-const))
        (:push (:reg ret))
        (:push (:reg n))
        (:mov n (:op - (:reg n) (:const 1)))
        (:mov ret (:label ret-fact))
        (:jmp (:label fact))
        ret-fact
        (:pop n)
        (:pop ret)
        (:mov val (:op * (:reg n) (:reg val)))
        (:jmp (:reg ret))
        ret-const
        (:mov val (:const 1))
        (:jmp (:reg ret))
        end
        (:op out (:reg val)))))

lovesan

(enable-xi-syntax)

(defmacro defoperator (name)
  `(eval-when (:compile-toplevel :load-toplevel :execute)
     (%symbol (sym-name ,name)))) ;;do nothing, just ensure interned symbol

(defoperator [lambda]) ;; an anonymous method
;; ::= lambda qualifier* lambda-args {declaration | documentation}* form*
;; qualifier ::= an atom
;; lambda-args ::= ( arg* [ . rest-arg ])
;; arg ::= ( arg-name specializer ) | arg-name
;; rest-arg ::= arg-name
;; arg-name ::= a symbol
(defoperator [quote]) ;; CL: QUTE
(defoperator [body]) ;; CL: PROGN
(defoperator [body1]) ;; CL: MULTIPLE-VALUE-PROG1
(defoperator [let]) ;; CL: LET
(defoperator [let*]) ;; CL: LET*
(defoperator [letr]) ;; ~ scheme letrec/define and CL: LABELS
(defoperator [letd]) ;; ~ CL:PROGV
(defoperator [letm]) ;; ~ CL: MACROLET + CL:SYMBOL-MACROLET
;; `tag' and `declare' are not operators
;;   but rather expressions that occur inside
;;    `body'(or implicit `body') forms
(defoperator [tag]) ;; goto label in `body'(or implicit `body') forms
(defoperator [declare]) ;; ~ CL:DECLARE
(defoperator [go]) ;; CL: GO
(defoperator [unwind-protect]) ;; CL: UNWIND-PROTECT
(defoperator [if]) ;; CL: IF
(defoperator [setv]) ;; `set variable[s]', ~ CL: SETQ + CL: (SETF VALUES)
(defoperator [the]) ;; ~ CL: THE
(defoperator [eval-when]) = ;; CL: EVAL-WHEN
(defoperator [block]) ;; = CL: BLOCK
(defoperator [return-from]) ;; = CL: RETURN-FROM
(defoperator [catch]) ;; = CL: CATCH
(defoperator [throw]) ;; = CL: THROW
(defoperator [mvcall]) ;; = CL: MULTIPLE-VALUE-CALL

(disable-xi-syntax)

lovesan

Разница между статической и динамической типизацией на самом деле не в том, когда происходят проверки типов - при компиляции, или в рантайме.

Это разница в подходе, в отношении к программам.

Существует известная цитата Робина Милнера:
-------------------------------------
 Well-typed programs never go wrong.
-------------------------------------
В этом вся статика, в этом весь хаскель и подобные языки. И в этом причина их переусложненности, и всех неудобств при их использовании для написания real-world программ.

В противопоставление, приведу цитату из стандарта Common Lisp:
http://www.lispworks.com/documentation/HyperSpec/Body/f_error.htm
-------------------------------------
 (defun wargames:no-win-scenario ()
   (if (error "pushing the button would be stupid."))
   (push-the-button))

In this scenario, there should be no chance that error will return and the button will get pushed.
While the meaning of this program is clear and it might be proven `safe' by a formal theorem prover, such a proof is no guarantee that the program is safe to execute. Compilers have been known to have bugs, computers to have signal glitches, and human beings to manually intervene in ways that are not always possible to predict. Those kinds of errors, while beyond the scope of the condition system to formally model, are not beyond the scope of things that should seriously be considered when writing code that could have the kinds of sweeping effects hinted at by this example.
-------------------------------------

Проблема в том, что хаскель и подобные языки целиком и полностью полагаются на абстракции. И строят из них другие абстракции, которые полностью закрывают предыдущие, и так далее. А это неправильное использование абстракций, особенно в контексте Software Engineering.

Потому что абстракции всегда текут.
http://www.joelonsoftware.com/articles/LeakyAbstractions.html

Смысл этой фразы в том, что абстракция это средство для уменьшения количества сущностей, которых необходимо держать в голове при решении какой-либо подзадачи в данный конкретный момент времени, но абстрагирование это ни в коем случае не отделение нижних слоев системы от вышележащих плотной стеной. Это просто не работает.

Если язык не учитывает класс аппаратных платформ, на которых он будет запускаться, если у него сферическая категориальная семантика в вакууме, которая совершенно не учитывает реальные проблемы и потребности, возникающие в процессе разработки и поддержки программ, он просто нежизнеспособен, неудобен и непрактичен, и является просто игрушкой, хотя, возможно, и красивой. И в таком случае, не называйте его "языком программирования".

lovesan

Вот за что ненавижу сишечку, среди прочего, так это за подобное говно:

int (*(*foo)(void ))[3]

Хуй разберешь, блядь, что это за хуйня. А если уж в отрыве от контекста, то вообще вещайся.

Но еще больше я ненавижу воннаби-хэцкеров и воннаби-системщиков, которые любят писать подобный код(наряду с говном типа *a++ = *b++).

Я когда-то давно тоже думал, что это ебать охуеть как круто, так писать на сишечке, типа, сразу видно что ты тру хэцкер. Но потом, блять, начал понимать соглашения именования MS, и все эти ихние тайпдефы, от CHAR до каких-нибудь LPOVERLAPPED_COMPLETION_ROUTINE.

btw: http://cdecl.org/

А еще я, кстати, поэтому же терпеть не могу уебанские именования фукций в POSIX и вообще в юниксах, и мне приятны именования винды, хоть они и длинные. Всякие там `mmap', `fcntl' и прочие `creat', `brk' и `getpgrp'(классный рандомный набор букв! в сисколлах линукса есть имена и круче!) мало того, что уебанско "по-хэккерски" выглядят, так их еще и хуй вспомнишь как они называются, когда они нужны, а уж вычислить по названию функции о ее назначении - про это я вообще не говорю даже;

В противоположность, на винде - CreateFileMapping, MapViewOfFile, CreateFile и DeviceIoControl и пр. - все понятно сразу, и запоминается легко.

Кстати, стиль именования функций в винапи на самом деле похож на лисповый, за исключением того, что `CamelCase', а не `lisp-case'.

lovesan

;; Главная Проблема Емакса - угребищность дефолтных настроек.
;;
;;   Вот без всего нижеследующего
;;     писать на нём под винду вообще совершенно
;;       невозможно.


;; Почему вот это нельзя было дефолтно сделать - для меня загадка.
(set-language-environment 'UTF-8)
(setq default-buffer-file-coding-system 'utf-8-unix)

;; На дворе 2011, штук 5 разных продакшн-квалити dvcs,
;;  все дела, а емакс по дефолту засирает все бэкапами. Круто, че.
(setq-default make-backup-files nil)

;; просто полезная фича
(setq-default auto-save-defaults t)

;; за табы в коде надо отрубать руки. Емакс этого правда не знает.
(setq-default indent-tabs-mode nil)

;; дефолтно - 8 вроде, не помню
(setq-default tab-width 4)

;; вот эта переменная для меня была вообще открытием.
;; я хз сколько искал как это убогое подобие консольного курсора,
;; которое емакс по дефолту рисует, в нем вырубить.
;; причем искал так долго, что уже даже
;; окончательно забил болт и смирился, но в итоге как-то
;; случайно обнаружил.
(setq w32-use-visible-system-caret t)

;; ну без этого вообще никуда. Дефолтные хоткеи на тему копипаста
;;  это вообще какой-то ад. Нет, я понимаю, тру хэккеры не копипастят
;;   вообще, но блять!
(cua-mode)

lovesan

// Из всех фич C# 4 меня больше всего радуют
    // вот эти вот "мультиметоды для бедных".
    // Конечно, это не CLOS с ее комбинаторами методов и прочим,
    // но тоже ничего.
    class Foo
    {
        public void DoSomething(Bar bar, Baz baz)
        {
            Console.WriteLine("Bar + Baz");
        }

        public void DoSomething(Baz baz, Bar bar)
        {
            Console.WriteLine("Baz + Bar");
        }

        public void DoSomething(Object x, Object y)
        {
            // фишка в 'dynamic'
            // тип резолвится в рантайме.
            dynamic _x = x;
            dynamic _y = y;
            DoSomething(_x, _y);
        }
    }

    class Bar { }

    class Baz { }

    class Program
    {        
        static void Main(string[] args)
        {
            Foo foo = new Foo();
            Object bar = new Bar();
            Object baz = new Baz();            
            foo.DoSomething(bar, baz);
            foo.DoSomething(baz, bar);
            // ==> Bar + Baz
            //     Baz + Bar
        }
    }