Собственно, с этим все понятно и у меня никогда проблем с ковариантностью не было. А вот контравариантность -- она вроде как есть, даже в стандартной библиотеке Scala используется: E>
E>abstract trait Function1 [-T1, +R] extends java.lang.Object with scala.ScalaObject
E>
E>но, блин, сходу вспомнить, что она означает и придумать какой-то пример ее использования -- не получается.
Что такое Function1, довольно просто объяснить.
Это, насколько я понял, функция с одним аргументом, запакованная в объект; в аннотации вариантности [-T1, +R] закодированы обычные правила подтипизации функций. Над ними нужно пару раз помедитировать, но на самом деле ничего сложного нет: тип функций a' -> b' будет подтипом a -> b тогда, когда b' является подтипом b и a является подтипом a'. Почему так? Допустим, мы передаем функцию как аргумент (псевдокод):
class Animal : Object {}
class Banana : Plant {}
class Apple : Plant {}
class Elephant : Animal {}
function foo(f : Plant->Animal)
{
Animal animal = f(new Banana);
}
function ok(x : Fruit) : Elephant
{
...
return new Elephant;
}
function bad1(x : Apple) : Animal
{
...
}
function bad2(x : Plant) : Object
{
...
}
...
foo(ok); // т.к. банан - тоже фрукт, ok умеет с ним работать.
// т.к. слон - тоже животное, foo сможет обработать возвращенное значение
foo(bad1); // bad1 не справится с бананом, она умеет есть только яблоки
foo(bad2); // foo не поймет, что ей вернула функция bad2,
// она ожидала животное, а получила непонятный "объект"
Сложно сказать, как скажутся изменения, касающиеся синтаксиса туплов, модификаторов private/protected и аннотаций. Но вот появление конструкций x += 1 радует
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[7]: [ANN] Scala 2.4.0: очередные изменения языка
Здравствуйте, eao197, Вы писали:
E>А применять или хотя бы помнить, где применять, нужно. Т.к. вариантность и ограничения на типы параметров обобщенных классов/методов -- обязательный минимум знаний для написания обобщенного кода в Scala.
На самом деле не обязательно. Когда ты будешь сталкиваться с конкретными случаями, а не с абстрактными рассуждениями, то и проблем не будет. Все будет очевидно.
E>Кстати, в C++ и D этих заморочек нет и в помине. Не говоря уже про динамически типизированные языки.
Незнаю как в Ди, а в С++ есть ковариантность для типов возвращаемых значений виртуальных методов. Эдакий не системный подход. Просто напоролись на реальную поторебность и решили прикрутить.
В любом случае практика показывает, что без ко/контрвариантности можно прекрасно жить на практике. А когда в них возникает реальная потребность, то и объяснять ничего не приходится.
E>К сожалению, на данном историческом этапе они совершенно не совместимы. Т.е. нужно либо писать на Phobos и не использовать Tango, либо наоборот.
Хм. Весма странно. А что мешает импортировать часть типов оттуда, а часть оттуда?
VD>>Везет тебе. А страступ считает, что свременный С++ появился где-то в 1994-ом. VD>>Чем ты пользовался то?
E>Turbo C++ 1.0 (это где-то 92-й), затем долго Borland C++ 2.0. Где-то же в 92-м, 93-м попадался в руки Zortech C++. С 95-го еще и Watcom C++.
Ты мне фигню то городи. "Дизайн и эволюция" были написана в 1994 году. В этой книге туча ссылок на то, что основные вещи шаблонов и многие другие решения были приняты только в 94 году. Без этого С++ был ближе к "С с классами" нежели к современному С++.
Что ты там мог учить до 94-го я себе даже предсвить не могу. Описание классов что ли?
VD>>Ну, до 1994-то на ПиСи компиляторов того что сейчас называют С++ попросту не было. Что то ты выдумывашь (по крайней мере с датами).
E>См. свидетельства очевидцев
Ну, им точно виднее чем Страуструпу.
Они даже Турбо С++ за С++ считают.
E>Я говорил про двухлетнее изучение C++. На Scala и D я потратил где-то по году. Так что год у меня в запасе еще есть.
Ты вообще что-то весьма странное говоришь. Рассказываешь о двухлетнем изучении С++ 2.0 в котором единственное что можно было изучать это множественное наследование (до 1994 года в С++ практически ничего не было). К тому же по всей видимости С++ у тебя был первым ООЯ. А Ди у тебя уже минимум 3-й язык. Не уж то на его изучение тоже надо два года?
E>С переменным успехом. Иногда удобнее, чем на C++, иногда нет. В общем, не произошло еще такого озарения, чтобы я сам себе сказал -- вот этот язык теперь мой выбор.
Ясно.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
eao197,
E>Сложно сказать, как скажутся изменения, касающиеся синтаксиса туплов, модификаторов private/protected и аннотаций.
Определённо, новые туплы мне очень нравятся. Но на данный момент написать что-то вроде
val obj = new Obj
val s = "String"
val x = 10
val t = (s, x)
obj.fn(s, x) // These two expressions
obj.fn(t) // are equivalent
не получится. Вместо этого последняя строчка должна выглядеть более громоздко:
Function.tupled(&obj.fn)(t)
Java-style аннтотации определённо лучше чем
[Annotation]TheClass[Param]
И ещё мне нравится скалистый интерпретатор, где можно лепить типы и многострочные определения, в отличие от GHCi 8-)
E>Но вот появление конструкций x += 1 радует
Ну, это и раньше можно было легко ручками определить:
Здравствуйте, eao197, Вы писали:
E>2.4.0 ChangeLog
E>Сложно сказать, как скажутся изменения, касающиеся синтаксиса туплов, модификаторов private/protected и аннотаций. Но вот появление конструкций x += 1 радует
Ты лучше скажи не хочешь ли попробовать что написать на Скале?
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[2]: [ANN] Scala 2.4.0: очередные изменения языка
Здравствуйте, VladD2, Вы писали:
E>>2.4.0 ChangeLog
E>>Сложно сказать, как скажутся изменения, касающиеся синтаксиса туплов, модификаторов private/protected и аннотаций. Но вот появление конструкций x += 1 радует
VD>Ты лучше скажи не хочешь ли попробовать что написать на Скале?
Вопрос не простой. Мне самому Scala очень симпатична во многих местах, но далеко не во всех. Есть моменты, с которыми у меня пока не все гладко (например, я постоянно путаюсь в понятии контравариантности и механизм линеаризации так же слегка напрягает).
Поэтому я сейчас больше склоняюсь к D, т.к. он кажется более простым, особенно с моим C++ным опытом. Пишу пока маленькие тестовые программки на обоих языках, когда время позволяет. Присматриваюсь. Что будет выбрано в результате пока не знаю, т.к. у каждого из них есть как свои большие достоинства, так и недостатки.
Но и особой спешки в выборе пока так же нет -- оба языка интенсивно развиваются и не стабилизировались пока. Не хочется на самом себе шишки набивать, т.к. будем посмотреть.
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[3]: [ANN] Scala 2.4.0: очередные изменения языка
Здравствуйте, eao197, Вы писали:
E>Вопрос не простой. Мне самому Scala очень симпатична во многих местах, но далеко не во всех. Есть моменты, с которыми у меня пока не все гладко (например, я постоянно путаюсь в понятии контравариантности и механизм линеаризации так же слегка напрягает).
С ковариантностью сапое приятное то, что ей можно не пользоваться.
E>Поэтому я сейчас больше склоняюсь к D, т.к. он кажется более простым, особенно с моим C++ным опытом. Пишу пока маленькие тестовые программки на обоих языках, когда время позволяет. Присматриваюсь. Что будет выбрано в результате пока не знаю, т.к. у каждого из них есть как свои большие достоинства, так и недостатки.
Незнаю, Да на сегодня — это С++ вид в профиль. Ничего приципиально нового он не дает. Такой же не безопасный язык с теми же парадигмами. Чуть проще — это не приемущество, по-моему.
E>Но и особой спешки в выборе пока так же нет -- оба языка интенсивно развиваются и не стабилизировались пока. Не хочется на самом себе шишки набивать, т.к. будем посмотреть.
А как же релиз Ди?
ЗЫ
Так и прождешь всю жизнь у меоря погоды.
Попробовал бы что ли ради разнобразия по проектику (мелкому) на каждом из них залудить.
Опыт очень интересный.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[4]: [ANN] Scala 2.4.0: очередные изменения языка
Здравствуйте, VladD2, Вы писали:
E>>Вопрос не простой. Мне самому Scala очень симпатична во многих местах, но далеко не во всех. Есть моменты, с которыми у меня пока не все гладко (например, я постоянно путаюсь в понятии контравариантности и механизм линеаризации так же слегка напрягает).
VD>С ковариантностью сапое приятное то, что ей можно не пользоваться.
С ковариантностью самое приятное то, что она с ходу понятна (ну в крайнем случае легко восстановить в памяти ее суть). А вот с контравариантностью лично у меня гораздо сложнее.
VD>А как же релиз Ди?
А после релиза встал еще более важный вопрос -- Phobos или Tango. Я лично ставлю на Tango.
VD>ЗЫ
VD>Так и прождешь всю жизнь у меоря погоды.
Я пользуюсь C++ с 93-го года практически постоянно. А начал изучать я его с конца 91-го. Имхо, потраченные 2 года на освоение языка, который обеспечивает мое нормальное существование уже в течении 13-ти лет себя давным-давно окупили. Если я буду сейчас еще года два выбирать между Scala и D, а затем еще 13-ть лет нормально зарабатывать с их помощью, то я буду считать это удачным выбором.
VD>Попробовал бы что ли ради разнобразия по проектику (мелкому) на каждом из них залудить.
Лудим потихоньку.
VD>Опыт очень интересный.
Я знаю.
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[5]: [ANN] Scala 2.4.0: очередные изменения языка
Здравствуйте, eao197, Вы писали:
E>С ковариантностью самое приятное то, что она с ходу понятна (ну в крайнем случае легко восстановить в памяти ее суть). А вот с контравариантностью лично у меня гораздо сложнее.
А в чем разница? Хотя опять же не пользуйся делов то...
VD>>А как же релиз Ди?
E>А после релиза встал еще более важный вопрос -- Phobos или Tango. Я лично ставлю на Tango.
Это библиотеки что ли?
E>Я пользуюсь C++ с 93-го года практически постоянно. А начал изучать я его с конца 91-го.
Везет тебе. А страступ считает, что свременный С++ появился где-то в 1994-ом.
Чем ты пользовался то?
E> Имхо, потраченные 2 года на освоение языка, который обеспечивает мое нормальное существование уже в течении 13-ти лет себя давным-давно окупили.
Ну, до 1994-то на ПиСи компиляторов того что сейчас называют С++ попросту не было. Что то ты выдумывашь (по крайней мере с датами).
В прочем, какое это отношение имеет к вопросу? Или ты намекаешь, что Скалу и/или Ди ты навереваешся изучать еще 5 лет?
E> Если я буду сейчас еще года два выбирать между Scala и D, а затем еще 13-ть лет нормально зарабатывать с их помощью, то я буду считать это удачным выбором.
Да ты уже Ди больше года обсуждаешь.
VD>>Попробовал бы что ли ради разнобразия по проектику (мелкому) на каждом из них залудить.
E>Лудим потихоньку.
Ну и как прогресс? Вот это очень интересно.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[6]: [ANN] Scala 2.4.0: очередные изменения языка
Здравствуйте, VladD2, Вы писали:
E>>С ковариантностью самое приятное то, что она с ходу понятна (ну в крайнем случае легко восстановить в памяти ее суть). А вот с контравариантностью лично у меня гораздо сложнее.
VD>А в чем разница? Хотя опять же не пользуйся делов то...
Формально говоря, если есть объявление ковариантности по параметру:
class Stack[+T] { ... }
и T является подтипом S, то Stack[T] является подтипом Stack[S]. Если же есть объявление контравариантности:
class Stack[-T] { ... }
и T являются подтипом S, то Stack[S] является подтипом Stack[T]. Вот такое вот объяснение.
Если же переходить на нормальный человеческий язык, то в случае контравариантности, можно делать так:
object T1 extends Application
{
import scala.collection.immutable.Stack
class Payment {}
class DangerousPayment extends Payment {}
def addPaymentTo( p: Payment, storage: Stack[Payment] ) {}
var dangerousPaymentStorage = new Stack[ DangerousPayment ]
val nextPayment = new DangerousPayment
addPaymentTo( nextPayment, dangerousPaymentStorage )
}
Здесь вызов addPaymentTo является легальным, т.к. DangerousPayment является подтипом Payment и Stack[DangerousPayment] является подтипом Stack[Payment]. Собственно, с этим все понятно и у меня никогда проблем с ковариантностью не было. А вот контравариантность -- она вроде как есть, даже в стандартной библиотеке Scala используется:
abstract trait Function1 [-T1, +R] extends java.lang.Object with scala.ScalaObject
но, блин, сходу вспомнить, что она означает и придумать какой-то пример ее использования -- не получается.
А применять или хотя бы помнить, где применять, нужно. Т.к. вариантность и ограничения на типы параметров обобщенных классов/методов -- обязательный минимум знаний для написания обобщенного кода в Scala.
Кстати, в C++ и D этих заморочек нет и в помине. Не говоря уже про динамически типизированные языки.
E>>А после релиза встал еще более важный вопрос -- Phobos или Tango. Я лично ставлю на Tango.
VD>Это библиотеки что ли?
Да. Phobos -- это стандартная библиотека, которая идет в поставке компилятора DMD. Но очень ограниченная. В частности, в ней нет таких жизнено важных для меня вещей, как mutex и condition variables. Создана и развивается силами самого Вальтера Брайта. Tango -- это попытка создать альтернативную стандартную библиотеку для D, которая бы полностью заменила Phobos. Разрабатывается силами коммунити и, поэтому, гораздо более продвинутая, чем Phobos.
К сожалению, на данном историческом этапе они совершенно не совместимы. Т.е. нужно либо писать на Phobos и не использовать Tango, либо наоборот.
E>>Я пользуюсь C++ с 93-го года практически постоянно. А начал изучать я его с конца 91-го.
VD>Везет тебе. А страступ считает, что свременный С++ появился где-то в 1994-ом. VD>Чем ты пользовался то?
Turbo C++ 1.0 (это где-то 92-й), затем долго Borland C++ 2.0. Где-то же в 92-м, 93-м попадался в руки Zortech C++. С 95-го еще и Watcom C++.
E>> Имхо, потраченные 2 года на освоение языка, который обеспечивает мое нормальное существование уже в течении 13-ти лет себя давным-давно окупили.
VD>Ну, до 1994-то на ПиСи компиляторов того что сейчас называют С++ попросту не было. Что то ты выдумывашь (по крайней мере с датами).
.
VD>В прочем, какое это отношение имеет к вопросу? Или ты намекаешь, что Скалу и/или Ди ты навереваешся изучать еще 5 лет?
Я говорил про двухлетнее изучение C++. На Scala и D я потратил где-то по году. Так что год у меня в запасе еще есть.
E>>Лудим потихоньку.
VD>Ну и как прогресс? Вот это очень интересно.
С переменным успехом. Иногда удобнее, чем на C++, иногда нет. В общем, не произошло еще такого озарения, чтобы я сам себе сказал -- вот этот язык теперь мой выбор.
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[8]: [ANN] Scala 2.4.0: очередные изменения языка
Здравствуйте, 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] { ... }
который позволяет записывать в коммуникационный канал какие-то объекты.
Далее, у нас есть функция, которая позволяет записать некий отчет (список строк) в коммуникационный канал, принимающий строки:
Но, пусть где-то у нас есть объект 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++.