?

Log in

uncheckedCast - Scala, Java, JVM и другое [entries|archive|friends|userinfo]
Scala, Java, JVM и другое

[ website | Об этом блоге ]
[ userinfo | livejournal userinfo ]
[ archive | journal archive ]

uncheckedCast [Oct. 8th, 2008|10:30 pm]
Scala, Java, JVM и другое

levin_matveev

[stepancheg]
[Tags|, , ]

Про uncheckedCast в bolts я, кажется, ещё не писал.

Метод uncheckedCast из класса параметризованного A делает экземпляр класса, параметризованного B. Реализован он примерно так:
class SomeClass<A> {
  <B> SomeClass<B> uncheckedCast() { return (SomeClass<B>) this; }
}

Такой метод есть у классов ListF, MapF, Option, Tuple2 и т. п.

Этот метод очень удобно использовать, когда не хочется по-честному параметризовать класс. Например, есть DAO, который возвращает список каких-то объектов, например, Car extend Washable, если это код проекта автомойки, и Plate extend Washable, если это код посудомоечной машины. Эти проекты имеют очень похожую структуру таблиц, поэтому код DAO у них общий. Вот его интерфейс:
interface WashableDao {
  ListF<Washable> findWashables();
}

В принципе, этот DAO можно было бы параметризовать как W extends Washable, но это делать не всегда удобно, т. к. например, вслед за DAO придётся параметризовать manager, и ещё много чего, и везде за собой эти параметры таскать.

Далее, в какой-то момент надо работать в этим списком как со списком тарелок. Стандартного способа для этого нет. В bolts можно писать так:
ListF<Plate> plates = washableDao.findWashables().uncheckedCast();

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

Уточненяю: это запрещено языком Java:
ListF<Plate> plates = (ListF<Plate>) washableDao.findWashables();

Спасибо разработчикам из Sun, реализовавших generics через erasure, благодаря чему работают такие конструкции.

Да, я знаю, что можно было написать
ListF<? extends Washable> findWashables();

Но это ещё менее удобно. И вообще, везде явно писать типы неудобно, uncheckedCast — это такой компромисс между строгой типизацией в Java 1.5 и отсутствием типизации в Java до 1.5.
LinkReply

Comments:
[User Picture]From: juan_gandhi
2008-10-08 07:26 pm (UTC)

  public static <X, Y, P extends Pair<X, Y>> Map<X, Y> Map(final Set

pairs) { final Function<P, Map.Entry<X, Y>> idmap = Function.id(); return new AbstractMap<X, Y>() { public Set<Entry<X, Y>> entrySet() { return idmap.map(pairs); } }; }



where
  public static <T, T1 extends T> Function<T1, T> id() {
    return new Function<T1, T>() {
      public T apply(T1 t) {
        return t;
      }
    };
  }



Note that there are no casts.

Edited at 2008-10-08 07:28 pm (UTC)
(Reply) (Thread)
[User Picture]From: stepancheg
2008-10-08 07:44 pm (UTC)
У тебя не заэксейплены параметры интерфейса Set в параметре pairs?

http://screencast.com/t/VU2QQYwrd6

Исправь, пожалуйста.
(Reply) (Parent) (Thread)
[User Picture]From: juan_gandhi
2008-10-08 09:55 pm (UTC)
Oops.


  public static <X, Y, P extends Pair<X, Y>> Map<X, Y> Map(final Set<P> pairs) {
    final Function<P, Map.Entry<X, Y>> idmap = Function.id();

    return new AbstractMap<X, Y>() {
      public Set<Entry<X, Y>> entrySet() {
        return idmap.map(pairs);
      }
    };
  }
(Reply) (Parent) (Thread)
[User Picture]From: stepancheg
2008-10-09 12:12 am (UTC)
Что этот пример показывает?

Set пересоздаётся внутри idmap.map. Тогда можно было сделать и так:

new HashSet[Entry[X, Y]](pairs)

Никакой магии. С другой стороны, если было бы написано

P extends Pair[? extends X, ? extends Y]

Ни твой пример, ни new HashSet бы не сработали, в отличие от uncheckedCast.
(Reply) (Parent) (Thread)
[User Picture]From: _navi_
2008-10-08 07:27 pm (UTC)
А разве Class.cast и Class.asSubclass для этой цели не подходят?
(Reply) (Thread)
[User Picture]From: stepancheg
2008-10-08 07:41 pm (UTC)
Это можно сделать разными способами. Основные мои мысли:

— Не надо верить тем, кто запрещает кастить из List[A] в List[B]
— Иметь uncheckedCast методом списка самый удобный способ для такой операции
(Reply) (Parent) (Thread)
[User Picture]From: _navi_
2008-10-08 07:43 pm (UTC)
ну просто мне настолько нечасто приходилось пользоваться этими явными кастами, что использование Class.cast/Class.asSubclass было достаточно удобным (и не оправдывало добавление нового метода). Хотя, конечно, YMMV.
(Reply) (Parent) (Thread)
[User Picture]From: stepancheg
2008-10-08 07:50 pm (UTC)
Это сильно зависит от задач и используемых подходов, наверное. Мы стали писать uncheckedCast всего пару месяцев назад, до этого особых проблем тоже не испытывали. Сейчас слово uncheckedCast используется в коде главного проекта аж 34 раза. Ещё тут работает такое свойство мира — пока не поездишь на BMW, Лада кажется хорошей машиной.
(Reply) (Parent) (Thread)
[User Picture]From: _navi_
2008-10-08 07:31 pm (UTC)
кстати, про bolts ты где-нибудь рассказывал (по тегу находит только ещё один пост в levin_matveev), и я на что-то важное не подписан?
(Reply) (Thread)
[User Picture]From: stepancheg
2008-10-08 07:37 pm (UTC)
Нет, не рассказывал. Собираюсь.
(Reply) (Parent) (Thread)