Re[8]: [ANN] Scala 2.4.0: очередные изменения языка
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 19.03.07 11:41
Оценка:
Здравствуйте, palm mute, Вы писали:

PM> Собственно, с этим все понятно и у меня никогда проблем с ковариантностью не было. А вот контравариантность -- она вроде как есть, даже в стандартной библиотеке Scala используется:

E>>
E>>abstract trait Function1 [-T1, +R] extends java.lang.Object with scala.ScalaObject
E>>

E>>но, блин, сходу вспомнить, что она означает и придумать какой-то пример ее использования -- не получается.

PM>Что такое Function1, довольно просто объяснить.


За ссылочки спасибо, за попытку объяснения Function1 так же, хотя путаница с типами вызвала свои сложности .

Вообще же хороший пример контравариантности есть где-то в ScalaByExample или ScalaOverview, или ScalaReference, или ScalaTutorial (вообще, что касается документации, то одни и те же фрагмены, имхо, кочуют из документа в документ, практически 1 в 1 ):

Итак, пусть у нас есть обобщенный класс:
class IOChannel[-T] { ... }

который позволяет записывать в коммуникационный канал какие-то объекты.

Далее, у нас есть функция, которая позволяет записать некий отчет (список строк) в коммуникационный канал, принимающий строки:
def storeReportTo( report: List[String], receiver: IOChannel[String] ) { ... }


Самый простой способ использования storeReportTo -- это передача ему объекта именно IOChannel[String]:
def openOrCreateReportFile(): IOChannel[String ] = { ... }

val report: List[String] = buildReport
val reportFile: IOChannel[String] = openOrCreateReportFile

storeReportTo( report, reportFile )


Но, пусть где-то у нас есть объект IOChannel[AnyRef] -- поскольку он может записывать любой объект, значит и строи он способен записывать. Значит, его можно попробовать передать в storeReportTo:
def findAppropriateTargetChannel(): IOChannel[AnyRef] = { ... }

val report: List[String] = buildReport
val reportChannel = findAppropriateTargetChannel

storeReportTo( report, reportChannel )


Вызов storeReportTo в этом случае оказывается легальным, поскольку благодоря контравариантности IOChannel[AnyRef] считается производным от IOChannel[String] -- т.е. способен использоваться там, где требуется IOChannel[String]. При всем при том String является производным от AnyRef.

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

Но с ко/контравариантностью в Scala есть и еще другие сложности. Там есть такие понятия, как ковариантные позиции аргументов и контравариантные. К сожалению, это дело описывается только в ScalaReference и очень формальным языком (для меня, как дилетанта в математике это вообще очень тяжело читается). Вот здесь уже начинается гадание. Так, в ScalaReference приводится пример:
// Вот такое использование аргумента x в методе append недопустимо:
abstract class Vector[+a] {
  def append(x: Vector[a]): Vector[a]
    // **** error: illegal variance:
    // ‘a’ occurs in contravariant position.
}

// Должно быть так:
abstract class Vector[+a] {
  def append[b >: a](x: Vector[b]): Vector[b]
}


Когда начинаешь разбираться с частностями, до всего, вроде как, доходишь. Но вот нормальной целостной картины пока нет


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.