cake pattern practices
Jun. 10th, 2012 01:32 pm![[personal profile]](https://www.dreamwidth.org/img/silk/identity/user.png)
http://vpatryshev.blogspot.com/2012/06/cake-pattern-practices.html
Только что запостил. Там всё примитивно (надеюсь); если чего не хватает или неправильно, буду рад выслушать.
Только что запостил. Там всё примитивно (надеюсь); если чего не хватает или неправильно, буду рад выслушать.
no subject
Date: 2012-06-10 09:10 pm (UTC)Очень понравилось, что все крайне просто написано. Еще бы про селф-тайпы и получится замечательное эссе на тему того, как и за что мы любим Скалу. Спасибо :)
no subject
Date: 2012-06-10 09:45 pm (UTC)Абстрактные типа - может быть, но пока что на работе не сталкивался, в этих аппликативах с ними что-то не получается (а хотелось бы).
Последнее не понял. В смысле, различные имплементации подставлять?
no subject
Date: 2012-06-10 10:33 pm (UTC)Вот, например, разросся у меня кейк за время использования. Хочу из него вынуть пару слоев и вынести в отдельный объект, чтобы уменьшить каплинг (кейком хорошо прототипировать, но в нем все всех видят, поэтому быстро накапливается энтропия). С этим могут быть проблемы.
Конкретный пример. Есть кейк компилятора, в котором пасутся типы, деревья, блабла. Прямо в этом кейке сидел реификатор. Потом выяснилось, что реификатор хорошо бы вообще выщемить из компилятора, превратив в макрос, у которого отдельная вселенная со своими типами и деревьями. Т.е. тип вселенной тот же самый (scala.reflect.api.Universe), но инстанс другой (в компиляторе это переменная под названием global, а у макроса это c.universe, где с это переменная типа Context, которую передают в имплементацию макроса).
Нифига наверное не понятно, поясню на датафлове, который примерно такой. Тайпчекер тайпчекает Apply(fun, args), и обнаруживает, что fun ссылается на reify. Тайпчекер говорит: окей, вот у меня есть global, я сейчас создам new Context(global). А потом возьму этот контекст и передам его метод reify_impl. reify_impl говорит: отлично, делаем import c.universe._ и создаем AST, соответствующие результату.
Все прекрасно до того момента, как мы захотим вернуть результат reify_impl и отдать его обратно в тайпчекер. Внезапно оказывается что тип результата - _1156.Tree forSome { val _1156: scala.reflect.api.Universe } (это он так выводится, тип результата мы, как водится, опустили), а тайпчекеру нужен global.Tree. В 2.9 это сигнал к кровавому угару кастов (угар этот и называется bakery of doom), но в 2.10 есть выход при помощи dependent method types.
В 2.10 сигнатура нашего reify_impl запишется вот как: "def reify_impl(c: Context)(input_tree: c.universe.Tree): c.universe.Tree". Отлично смотрится, что же мне еще надо? Сейчас посмотрим.
Во-первых, чтобы уломать компилятор на тему того, что c.universe.Tree это ни что иное как global.Tree, надо запретить ему делать widen для типа параметра c. Можно это сделать вот так: "def reify_impl[C <: Context with Singleton](c: Context)..." (если я ничего не путаю). Можно вот так: "val c = new Context { val universe: global.type = global }; reify_impl(c)(tree)". Многабукф.
Во-вторых, этот с приходится всюду таскать с собой. Не передашь ведь просто tree в хелпер-метод, так как надо будет в сигнатуре хелпер-метода сказать, какой именно это Tree, а то опять получится _1774.Tree forSome blah. По похожим соображениям для dependent methods не работает эта-конверсия (преобразование в функциональные типы). Снова неудобно - сильно обрезаются возможности по абстрагированию. Так и до копипаста недолго.
Наконец, вся эта машинерия в особо адовых случаях ломается и приходится идти в Types.scala и допиливать проверки isSubType. Я это сам не делал, просто тихо сидел в сторонке с большими глазами, пока Мартин колбасил. На любителя, короче.
К чему я все это? Мне очень нравится кейк паттерн (вон сейчас на питоне фигачу его же), но у него есть определенные границы применимости. Интересно узнать как их расширить. Цитируя Мартина: "We believe in power" :)
no subject
Date: 2012-06-10 11:06 pm (UTC)Обычно решается с помощью верёвки, палки и тайп-лямбды. Отложил на попозже.
А в реале не встречалось (близко проходил, но проскочил). Наверное, надо будет тот случай тоже осветить (сорсов с собой дома нету).
no subject
Date: 2012-06-11 01:51 am (UTC)