Не о каких-нибудь там особо хитрых; в принципе, чуть ли не двоичных значений хватает, чтобы продемонстрировать.
Начнём, конечно, с Джавы. В которой сплошь и рядом, у "плохих программистов" встречается такое:
if (message inscanceof CancellationMessage) { application.cancelnahren(); }
else if (message instanceof EncouragementMessage) { galera.trabalha(); }
// etc
и хорошим программистам это не нравится, и они говорят "делегейшен давай", или "смартенумы давай!"
Делегейшен, это когда каждый параметр слишком широкого диапазона типов должен вдруг знать, что вот этот вот практически незнакомый тип однажды возьмёт да и обратится к ним, и надо для этого иметь особую форму (сиречь, сигнатуру), чтоб не подвести свой класс, а сделать, что положено (а там хоть не рассветай).
Ну или енум использовать - но енум контента не имеет, это константа... тогда люди ещё как поступают: в класс вставляют этот самый енум, "тип инстанса нашего класса".
class Message {
enum type {
CANCEL,
ENCOURAGE,
DGAF} myType;
....
}
...
switch(message.type()) {
case CANCEL: ...
case ENCOURAGE: ...
case DGAF: ...
}
и это кошернее, чем было бы писать
class mc = message.getClass();
if (mc.equals(CancelMessage.class)) { ... }
else if (....
В Скале же, на самом деле, не особо стесняются расписывать по классам, но на то есть другая причина:
unapply
, а ещё лучше сказать, линза (обратная сторона); с помощью её можно устраивать сравнение по образцу и, в зависимости от типа, выполнять какие-то действия с параметрами конструктора.
message match {
case CancelMessage(timeout: TimeInSeconds) => app.cancelato(timeout)
case EncourageMessage(text: String) => galera.listen(text); galera.trabalha
...
}
Фактически эта конструкция в некотором смысле помещает исполяемый, специфический для класса параметра, код немножко в контекст этого класса (видны только параметры конструктора).
В Скале есть немножко тенденция некоторые классы объявить более равными, например
Option[T]
,
Either[Left,Right]
- для них как бы некошерно употреблять кейсы, а надо использовать функциональную функцию
map
. В принципе, скальные библиотеки любят возвращать
Option[T]
, и тут-то бы и применять
map
, да штука в том, что в случае
None
ничего ни к чему применяться не будет. Так что приходится расписывать кейс. И со списками, что характерно, кейс приходится писать: как правило, разбивая ситуацию на два случая - пустой список или голова с хвостом, неважно, пустым или нет.
Так же и на Хаскеле - или мы матчим список, или
Maybe
, или data type.
И вот это вот "перечисление случаев" меня как-то смущает; нельзя ли для этого дела пристроить что-то вроде
map
? Но блин, это ж надо передавать, вообще говоря, по специальному исполнителю на каждый отдельный жизненный случай. Как в Джаве любят писать - лисинеры,
listeners
- они будут теперь здоровкаться на каждый чих.
Это практически cps, continuation passing style. Как в Джаваскрипте, если вы ещё помните, что такое
xhr
, а не вызываете что-нибудь там вроде
JQuery.doAjaxForMeHurry()
, то у вас как правило два-три таких слушателя: - пока читает, - когда закончили, - если ошибка. А могли бы написать (если б могли)
reset {
switch {
case STILL_READING: ...; break
case GOT_RESULT: ...; return
case ERROR: ...; return
}
shift(k) {
do {
var resp = XHR.doPost(myStuff)
k(resp)
}
}
}
Это было бы почти идеальное решение, да?
Не знаю, не знаю.