?

Log in

No account? Create an account

Зачем нужны имплисит макросы? - Excelsior — LiveJournal

May. 7th, 2013

11:06 pm - Зачем нужны имплисит макросы?

Previous Entry Share Next Entry

Comments:

From:zhengxi
Date:May 7th, 2013 09:31 pm (UTC)
(Link)
да, я ответ написал редактируя коментарий, одновременно с твоим вопросом :)
см.последнее предложение.

хотя... вот конкретно в Json - никак, т.к. я практически только MsgPack юзаю, то Json-сериализатор отстаёт по версиям.
Но там можно аналогично сделать.

Edited at 2013-05-07 09:35 pm (UTC)
(Reply) (Parent) (Thread)
[User Picture]
From:xeno_by
Date:May 7th, 2013 09:38 pm (UTC)
(Link)
Как я понимаю, в твоей реализации MsgPack.pack не является первоклассной сущностью, т.е. невозможно параметризироваться относительно pack[T] и на его основе создать pack[List[T]] как описано в примере выше с implicit def listSerializable, правильно?
(Reply) (Parent) (Thread)
From:zhengxi
Date:May 7th, 2013 09:50 pm (UTC)
(Link)
в смысле написать не "implicit object xxx extends MsgPack.AuxPacker[ObjectId]" как там у меня в тестах, а "implicit def xxx[T] = new MsgPack.AuxPacker[List[T]]" ?

чёрт знает, может и можно.

я только из этого поста узнал, что имплициты композируются :)
поэтому List и прочие Traversable и мой макрос тоже просто "знает", а, наверное, можно было и так попробовать.
(Reply) (Parent) (Thread)
[User Picture]
From:xeno_by
Date:May 7th, 2013 09:55 pm (UTC)
(Link)
Да, типа того, причем в теле AuxPacker[List[T]] заюзать реализацию pack[T]. Пока что для этого придется сделать xxx[T] макросом, который в своем раскрытии вызывает pack[T], что не очень удобно.

Кстати, что скажешь по поводу нашей недавней паперы про нативный фреймворк для сериализации в Скале: http://lampwww.epfl.ch/~hmiller/files/pickling.pdf?
(Reply) (Parent) (Thread)
From:zhengxi
Date:May 7th, 2013 10:00 pm (UTC)
(Link)
Да, типа того, причем в теле AuxPacker[List[T]] заюзать реализацию pack[T]. Пока что для этого придется сделать xxx[T] макросом, который в своем раскрытии вызывает pack[T], что не очень удобно.

а, тогда да.
или implicit macro или патчи от marten_de, чтобы макросы вызывать где попало.

Кстати, что скажешь по поводу нашей недавней паперы про нативный фреймворк

я попозже отвечу, ok?
много букв :)
(Reply) (Parent) (Thread)
[User Picture]
From:xeno_by
Date:May 7th, 2013 10:04 pm (UTC)
(Link)
Тут дело не в том, чтобы макросы вызывать где попало, а в том, что ты не сможешь написать: "implicit def xxx[T] = new MsgPack.AuxPacker[List[T]] { def packto(os: OutputStream, xs: List[T]) { for (x <- xs) pack[T] } }" потому, что pack[T] захочет прямо там же раскрыться, но не сможет этого адекватно сделать, т.к. он будет видеть просто какой-то тайп параметр T вместо конкретного типа.
(Reply) (Parent) (Thread)
[User Picture]
From:xeno_by
Date:May 7th, 2013 10:04 pm (UTC)
(Link)
Конечно, take your time! :)
(Reply) (Parent) (Thread)
From:zhengxi
Date:May 7th, 2013 10:26 pm (UTC)
(Link)
Очень вкусно выглядит, особенно упаковка/распаковка subclass'ов.
Сериализовать что-то вроде ADT надо достаточно часто (сейчас я это распаковываю в два прохода - первый раз достаю тип, а второй раз уже unpack[] с этим типом. пока таких мест не много, так что терплю:)

Вопрос - там в папере ссылка на репозиторий https://github.com/heathermiller/scala-pickling/
А в репозитории компилятор скалы целиком.
То есть это не библиотека, а такой специальный форк компилятора?
(Reply) (Parent) (Thread)
[User Picture]
From:xeno_by
Date:May 7th, 2013 10:31 pm (UTC)
(Link)
Форк был просто удобным форматом разработки. Если нам что-то надо было починить в компиляторе, мы просто патчили по живому и колбасили дальше вместо того, чтобы париться с мейнтейном отдельного форка компилятора и репозитория его бинарников. В достаточно близких планах зарелизить standalone библиотеку, которая скорее всего будет работать даже в 2.10.2+.

Edited at 2013-05-07 10:31 pm (UTC)
(Reply) (Parent) (Thread)
From:zhengxi
Date:May 7th, 2013 11:28 pm (UTC)
(Link)
Такая еретическая мысль:

Вот есть у вас в папере пример:
val unpickld = pickl.unpickle[Any] match {
  case Firefighter(name, since) => ...
  case x: Int => ...
...
}

Пример, возможно, далёк от практики, но сейчас важно будут только то, что параметр unpickle (тут Any) - это не-sealed class, а это уже не так далеко.
Получается, что тут будет задействован runtime unpickler, так?
Даже если ничего другого (кроме Firefighter и Int) тут не придётся распаковывать, это будет делаться через runtime reflection.

Дальше.
Эта ваша библиотека - хорошая попытка окончательного решения вопроса сериализации, и runtime unpicker, как последний островок тормознутости, рано или поздно будет заменён (неважно вами или форкерами) на динамическую генерацию JVM-байткода (или даже на компиляцию на лету Scala-кода), с периодической перегенерацией, если вдруг стал часто прилетать новый тип данных.

И встанет вопрос - а зачем тогда макросы? 3ачем вообще Scala?
Ведь эта часть будет работать так же быстро, как и код, сгенерённый макросами (ok, не сразу, после некоторого "прогрева"), и её можно сделать на старой доброй Java.
И почему такого до сих пор нет?
(Reply) (Parent) (Thread)
[User Picture]
From:xeno_by
Date:May 8th, 2013 06:55 am (UTC)
(Link)
Да, с не-sealed классами есть проблема в том плане, что хотелось бы во время компиляции искать всех их наследников, но для этого нет простого способа, поэтому приходится или как-то выкручиваться (что пока что получается не очень), или тормозить.

Для данного конкретного случая можно наколбасить клевый макрос, который полностью решит проблему, проэнумерировав возможные случае в компайл-тайме:
val unpickld = pickl.unpickle {
  case Firefighter(name, since) => ...
  case x: Int => ...
...
}
В принципе, там уже есть компиляция Скалы на лету. Генерится точно такой же код, что был бы сгенерирован в компайл-тайме, если был бы известен тип, а потом он компилируется тулбоксом. Пока что результаты компиляции не кэшируются, т.к. не успели, но это планируется.

Рантайм аналог так же быстро работать не будет, т.к. он не будет знать все типы, часть из которых сотрется во время erasure. Поэтому, как я понимаю, мы уделываем Kryo на сериализации коллекций (я сам в бенчмаркинге участия не принимал, поэтому насчет деталей не в курсе и говорю только свои гипотезы) - при всем желании вместо Vector[Int] Kryo видит Vector, поэтому он не сможет сгенерировать специализированный код. Предположим, в случае коллекций можно выкрутиться при помощи toArray, но, наверняка, возможны случаи, когда не выкрутишься.

Edited at 2013-05-08 06:56 am (UTC)
(Reply) (Parent) (Thread)
From:zhengxi
Date:May 9th, 2013 02:02 pm (UTC)
(Link)
да, ты прав.
хороший повод перейти на 2.10.2 :)
(Reply) (Parent) (Thread)