Comments 8
Ненормальное программирование
Как здорово вы угадали с хабом.
Вообще, интересная вещь, но только если количество сущностей в проекте over 9000, иначе излишнее усложнение не окупается удобством того же рефакторинга.
Как здорово вы угадали с хабом.
Вообще, интересная вещь, но только если количество сущностей в проекте over 9000, иначе излишнее усложнение не окупается удобством того же рефакторинга.
+2
Здесь мы сохраняем возможность рефакторинга. Все свойства представлены объектами, хранятся в именованных константах (val'ах). С точки зрения объявления «класса» получается не сильно больше, чем объявление обычного case class'а.
vs.
case class Person(
name: String,
address: Address
)
vs.
object Person{
val name = slot[String]("name")
val address = slot[Address]("address")
}
0
Все сугубо, ИМХО. «Правильной дорогой идете товарищи» (с) Одна из проблем сегодняшнего программирования, то, что объектом является аристотелева вещь с фиксированным набором свойств. Вот один из примеров, почему это сильно усложняет программирование сложных систем.
То, что вы описали, как я понял, похоже на путь к решению этой проблемы. Следующий шаг — осознать, что свойство != имя + значение, а является полноценным объектом, который проявляется во взаимодействии со свойствами других вещей.
Успехов.
Человек рождается с очень ограниченным набором свойств: иметь возраст, вес, рост, пищать, питаться и портить подгузник. Время идет, и он приобретает новые наборы свойств: ученик школы, покупатель, пассажир, солдат, студент, наемный работник, предприниматель, супруг, родитель и т.д. А возможно и не приобретает. Например, не каждый человек служит в армии, учится в вузе, женится и становится отцом или предпринимателем. Или утрачивает. Например, закончил учиться, отслужил в армии или развелся. Следовательно, один и тот же объект должен иметь возможность принадлежать разным классам и этот набор классов должен быть динамическим, т.е. изменяться в ходе эволюции объекта и самой программной системы. На набор классов, к которым относится объект, как правило, накладываются ограничения. Например. Чтобы стать солдатом, человек должен достичь 18 лет. А если человек студент то для того, чтобы стать мужем, необходимо сдать сопромат.
То, что вы описали, как я понял, похоже на путь к решению этой проблемы. Следующий шаг — осознать, что свойство != имя + значение, а является полноценным объектом, который проявляется во взаимодействии со свойствами других вещей.
Успехов.
+2
HList напоминает Union Type. Наверное мне пора серьёзнее посмотреть на Shapeless.
Не совсем понятно применение. Экономии на количестве классов в JVM не получается, потому что «object Person» создаст класс «Person$». Чтобы избежать copy-paste на однотипных операциях можно использовать дженерики, хоть там type erasure и ограничивает возможности узнавать тип в рантайме. Но в паре с Typeclass pattern (см. например мой блог) можно это обойти, да ещё и перенести обработку выбора кода для конкретного типа на этап компиляции.
Пример с delta был бы интересен. Особенно чем он отличается от
Не совсем понятно применение. Экономии на количестве классов в JVM не получается, потому что «object Person» создаст класс «Person$». Чтобы избежать copy-paste на однотипных операциях можно использовать дженерики, хоть там type erasure и ограничивает возможности узнавать тип в рантайме. Но в паре с Typeclass pattern (см. например мой блог) можно это обойти, да ещё и перенести обработку выбора кода для конкретного типа на этап компиляции.
Пример с delta был бы интересен. Особенно чем он отличается от
case class Person(val name: String, val address: Option[String])
val john = Person("John", None)
val john2 = john.copy(address = Some("22b Baker st")
0
1. UnionType (by Miles Sabin) используется для того, чтобы сформировать объединённый тип всех свойств, которые уже использовались в текущем объекте
(Здесь мы используем оператор
2. Экономия классов не входит в цели фреймворка. Суть заключается в разрезании целого класса на отдельные компоненты и возможность оперировать данными, используя эти компоненты (слоты) в качестве ключа.
3. Пример с delta. Пусть класс Person содержит 100 полей. И пусть среди этих полей есть свойство типа T: Numeric (например, Int, Double и т.п.). Тогда мы можем объявить специальный класс PropertyDelta, который несёт изменение этого свойства
Это может быть экономнее, чем копировать оставшиеся 99 полей (при сохранении в БД, при передаче по сети и т.п.). Кроме того, здесь мы явно видим, что именно изменилось, можем проверить допустимость изменения этого свойства согласно каким-либо правилам.
Теперь мы можем этот объект использовать для того, чтобы увеличить значение свойства на указанную величину:
Или немного поинтереснее:
type SlotsUnion = head.type with tail.SlotsUnion
(Здесь мы используем оператор
with
, который соответствует конъюнкции. Для проверки принадлежности мы инвертируем условие с помощью оператора <:< def get[SlotType<:SlotId[_](slotId:SlotType)(implicit ev: SlotSeq1#SlotUnion <:< SlotType) = ???
2. Экономия классов не входит в цели фреймворка. Суть заключается в разрезании целого класса на отдельные компоненты и возможность оперировать данными, используя эти компоненты (слоты) в качестве ключа.
3. Пример с delta. Пусть класс Person содержит 100 полей. И пусть среди этих полей есть свойство типа T: Numeric (например, Int, Double и т.п.). Тогда мы можем объявить специальный класс PropertyDelta, который несёт изменение этого свойства
case class SlotDelta[T:Numeric, S <: SlotId[T]](slotId:S, delta:T)
Это может быть экономнее, чем копировать оставшиеся 99 полей (при сохранении в БД, при передаче по сети и т.п.). Кроме того, здесь мы явно видим, что именно изменилось, можем проверить допустимость изменения этого свойства согласно каким-либо правилам.
Теперь мы можем этот объект использовать для того, чтобы увеличить значение свойства на указанную величину:
case class SlotDelta[T:Numeric, S <: SlotId[T]](slotId:S, delta: T) {
def addTo(oldValue:SlotValue[T, S]) =
SlotValue(slotId, implicitly[Numeric[T]].plus(oldValue.value, delta))
}
Или немного поинтереснее:
implicit class SlotValueEx[T:Numeric, S <: SlotId[T]] (slotValue:SlotValue[T, S]) {
def +(delta:T) =
SlotValue(slotValue.slotId, implicitly[Numeric[T]].plus(slotValue.value, delta))
}
+1
P.S. Вышеприведённый вариант — для общего случая, для Int, Double, BigNumber… и других T, для которых есть Numeric[T]. Если delta имеет известный тип, то можно и проще:
case class SlotDelta[S <: SlotId[Int]](slotId:S, delta: Int) {
def +:(oldValue:SlotValue[Int, S]) =
SlotValue(slotId, oldValue.value+ delta)
}
0
Спасибо за пояснения. Да, действительно интересный подход.
0
Sign up to leave a comment.
Конструирование типов в Scala