Здравствуйте, AndrewVK, Вы писали:
AVK>Алиасы не спасут. Вот смотри, есть в third party библиотеке некая фабрика с методом "IPet Get()". И что ты будешь делать, если у тебя IPet от IAnimal не отнаследован? Кастить? AVK>Наследование интерфейсов — неотъемлемая часть контракта, и современная тенденция скорее склонна контракт усложнять и делать более строгим (пре- и постусловия, инвариант и т.п.), нежели наоборот его упрощать.
Это конечно словоблудие всё, но скорее тендеция — упрощать контракт, в том числе и с помощью наследования. Это будет всяко лучше, чем получить неясный кортеж несвязных интерфейсов.
Здравствуйте, fddima, Вы писали:
F> Это конечно словоблудие всё, но скорее тендеция — упрощать контракт, в том числе и с помощью наследования. Это будет всяко лучше, чем получить неясный кортеж несвязных интерфейсов.
По усложнением я здесь понимаю расширение ограничительных возможностей.
... << RSDN@Home 1.2.0 alpha 5 rev. 52 on Windows 7 6.1.7601.65536>>
ВВ>И какое число знаков после запятой должно быть допустимо в идеальном языке?
Ну конечно же должны быть не убогие знаки после запятой, а абсолютно точные вычисления в обыкновенных дробях! Иначе этим идеальным язком ни один математик пользоваться не станет
Здравствуйте, AlexRK, Вы писали:
ВВ>>Гм, а что тогда такое тип по-твоему? ARK>Множество значений с именем (я говорю о номинативной типизации). Если метод требует тип с именем Int32, то Int16 ему передать нельзя.
Вообще отказ от номинативной типизации вовсе не означает, что у нас становится один тип. Скажем, a'->a'->a' и a'->a' это типы разные, хотя и структурные.
Если уж вести разговор об идеальных языках, то в идеальном языке не должно быть по крайней мере флоатов, ибо они ломают ER. А большинство числовых типов (но не все, ибо это невозможно) могут быть реализованы на базе примитива Integer (arbitrary precision).
ВВ>>Ленивые вычисления можно делать, например. Для обычных числовых типов результатом x > 5 будет _|_, если x это _|_. В случае с пеано далеко не обязательно, число может быть вычислено ровно настолько, насколько это нужно, и inf > 5 отработает как надо. ARK>Понятно. Правда, насколько распространены такие задачи... На современных промышленных ЯП такого тоже не сделаешь.
В промышленных языках и ленивых контейнеров нет (настоящих по крайней мере). Что ж теперь поделать.
ARK>>>А одной реализацией обойтись нельзя? Плюс-минус и остальные операторы у нас есть, берем и вычисляем синус численными методами. Или я чего-то не понял. ВВ>>В вычислениях используются различные константы, которые могут иметь разную точность. ARK>Да, я понял. Но это ведь вопрос эффективности, нет? Или принципиально невозможно вычислить синус, имея на руках только базовые операции?
Это не вопрос эффективности, это вопрос точности. Если у тебя какой-нибудь pi захардкожен в double, то мало того, что все числа на свете должны поддерживать арифметику с double, так еще и точность будет соответствующая.
Не говоря уж о том, что тригонометрические и гиперболические ф-ции могут иметь смысл и для комплексных чисел, а реализация вполне может отличаться, т.к. не все остальные операции могут для них иметь смысл.
Мне, честно, кажется, тут очень непросто все. Посмотри на Хаскелл, там есть генерик арифметика и перегруженные литералы, но товарищи даже gcd/lcm в отдельный класс засовывают.
ВВ>>Да и не для всех чисел, поддерживающих остальные арифметические операции, вычисление всяких синусов может иметь смысл. ARK>Наверное тут надо опять работать с предусловиями.
Ага, и чтобы описать эти предусловия, ты должен ввести свою абстракцию. Например, Transcendental. Вот тебе и "тип".
Здравствуйте, AndrewVK, Вы писали:
AVK>Здравствуйте, AlexRK, Вы писали:
ARK>>Алиасы уже тут обсуждались, не обязательно в каждом месте.
AVK>Алиасы не спасут. Вот смотри, есть в third party библиотеке некая фабрика с методом "IPet Get()". И что ты будешь делать, если у тебя IPet от IAnimal не отнаследован? Кастить?
Ну если брать язык без наследования интерфейсов, то такая запись означает, что Get() НЕ возвращает IAnimal в принципе и не реализует его методы. Аналогичная ситуация в C# — интерфейс IPet просто не отнаследован от IAnimal. Тут касти — не касти, ничего не сделаешь.
Кстати, еще момент. Мне не очень нравится ситуация, когда метод возвращает "не знамо что" — интерфейс, за которым непонятно какой класс. ИМХО, код верхнего уровня всегда должен знать конкретные типы (должно быть — "T Get()", где T — генерик-параметр класса, реализующий IPet). А вот "подчиненный" код может иметь дело с неизвестными для него типами. По-моему, в Ada только так и возможно, кстати.
AVK>Наследование интерфейсов — неотъемлемая часть контракта, и современная тенденция скорее склонна контракт усложнять и делать более строгим (пре- и постусловия, инвариант и т.п.), нежели наоборот его упрощать.
Согласен насчет усложнения контрактов. Но насчет наследования пока вашу точку зрения не готов принять.
Здравствуйте, Воронков Василий, Вы писали:
ВВ>Здравствуйте, AlexRK, Вы писали:
ВВ>>>Гм, а что тогда такое тип по-твоему? ARK>>Множество значений с именем (я говорю о номинативной типизации). Если метод требует тип с именем Int32, то Int16 ему передать нельзя.
ВВ>Вообще отказ от номинативной типизации вовсе не означает, что у нас становится один тип. Скажем, a'->a'->a' и a'->a' это типы разные, хотя и структурные.
Ну да. Но когда мы предусловием ограничиваем значение параметра, то тип этого параметра не меняется. Хотя если в широком смысле посмотреть, то можно и это считать новым типом.
ВВ>Если уж вести разговор об идеальных языках, то в идеальном языке не должно быть по крайней мере флоатов, ибо они ломают ER. А большинство числовых типов (но не все, ибо это невозможно) могут быть реализованы на базе примитива Integer (arbitrary precision).
Верно. Абсолютно однозначно плавающей запятой не должно быть, только фиксированная.
ARK>>>>А одной реализацией обойтись нельзя? Плюс-минус и остальные операторы у нас есть, берем и вычисляем синус численными методами. Или я чего-то не понял. ВВ>>>В вычислениях используются различные константы, которые могут иметь разную точность. ARK>>Да, я понял. Но это ведь вопрос эффективности, нет? Или принципиально невозможно вычислить синус, имея на руках только базовые операции?
ВВ>Это не вопрос эффективности, это вопрос точности. Если у тебя какой-нибудь pi захардкожен в double, то мало того, что все числа на свете должны поддерживать арифметику с double, так еще и точность будет соответствующая. ВВ>Не говоря уж о том, что тригонометрические и гиперболические ф-ции могут иметь смысл и для комплексных чисел, а реализация вполне может отличаться, т.к. не все остальные операции могут для них иметь смысл. ВВ>Мне, честно, кажется, тут очень непросто все. Посмотри на Хаскелл, там есть генерик арифметика и перегруженные литералы, но товарищи даже gcd/lcm в отдельный класс засовывают.
Думаю, что Pi должно быть не константой, а функцией с параметром, указывающим точность.
Вообще да, тут все сложно, я так — помечтать.
ВВ>>>Да и не для всех чисел, поддерживающих остальные арифметические операции, вычисление всяких синусов может иметь смысл. ARK>>Наверное тут надо опять работать с предусловиями.
ВВ>Ага, и чтобы описать эти предусловия, ты должен ввести свою абстракцию. Например, Transcendental. Вот тебе и "тип".
Здравствуйте, hi_octane, Вы писали:
ВВ>>И какое число знаков после запятой должно быть допустимо в идеальном языке? _>Ну конечно же должны быть не убогие знаки после запятой, а абсолютно точные вычисления в обыкновенных дробях! Иначе этим идеальным язком ни один математик пользоваться не станет
Здравствуйте, AndrewVK, Вы писали:
V>>Нафиг, нужен такой полиморфизм. IPet-ом может быть не только IAnimal, но и IBird, IReptiles, IFish ... AVK>Которые, в свою очередь, являются IAnimal?
Ну так какую иерархию наследования ты здесь предлагаешь?
Здравствуйте, AndrewVK, Вы писали:
ARK>>Алиасы уже тут обсуждались, не обязательно в каждом месте. AVK>Алиасы не спасут. Вот смотри, есть в third party библиотеке некая фабрика с методом "IPet Get()". И что ты будешь делать, если у тебя IPet от IAnimal не отнаследован? Кастить?
Third party библиотека должна тогда возвращать (IPet IAnimal), а не просто IPet.
Ну два варианта:
1) Задавать точность именно таких чисел, через указание числа разрядов в числителе или знаменателе или в момент использования. Типа там Math.PI(2000). Или Math.Precision = 2000; Math.PI
2) Сворачивать Number * PI в "символьной" форме в Number, который не вычисляет PI, а знает что это функция, и лениво накапливать такие операции, вычисляя с нужной точностью и подставляя в момент Number.GetDouble() или Number.ToString("F20"). Это будет совсем тру.
А чтобы математики рассматривали язык как совсем годный, нужно ещё числа научить размерности за собой таскать и правильно их преобразовывать вместе со значениями.
Здравствуйте, AlexRK, Вы писали:
ARK>Ну если брать язык без наследования интерфейсов, то такая запись означает, что Get() НЕ возвращает IAnimal в принципе и не реализует его методы.
Это все понятно. Но делать то что?
ARK> Аналогичная ситуация в C# — интерфейс IPet просто не отнаследован от IAnimal. Тут касти — не касти, ничего не сделаешь.
И это будет трактоваться как ошибка.
ARK>Кстати, еще момент. Мне не очень нравится ситуация, когда метод возвращает "не знамо что" — интерфейс, за которым непонятно какой класс.
Это называется абстракция. Предлагаешь и ее отменить?
ARK> ИМХО, код верхнего уровня всегда должен знать конкретные типы (должно быть — "T Get()", где T — генерик-параметр класса, реализующий IPet).
Т.е. возможность создания плагинов и аналогичных механизмов хороним в зародыше?
... << RSDN@Home 1.2.0 alpha 5 rev. 52 on Windows 7 6.1.7601.65536>>
Здравствуйте, AndrewVK, Вы писали:
AVK>Здравствуйте, Воронков Василий, Вы писали: ВВ>>Third party библиотека должна тогда возвращать (IPet IAnimal), а не просто IPet. AVK>Должна. Вот только с наследованием я могу заставить так делать, а без него — только верить, что меня не забудут.
Вопрос в общем-то остается прежним — зачем *заставлять* так делать? В реальности, это единственный вопрос, на который и нужно ответить в рамках этой темы.
К тому же все эти примеры с GetPet/GetItems немного странные. Либо это вообще неполиморфные функции, и тогда они должны возвращать конкретный класс, а не интерфейс, либо они являются членами, скажем, генерик-класса, и тогда они тем более не будут возвращать интерфейс, а скорее некое T, на которое будут навешаны констрейнты.
Здравствуйте, AndrewVK, Вы писали:
AVK>Здравствуйте, Воронков Василий, Вы писали: ВВ>>Ну так какую иерархию наследования ты здесь предлагаешь? AVK>Никакую. Уж сколько лет твердили миру — иерархии идут от конкретных задач, а не из пальца. "ООП это про поведение" (С) Синклер.
Вот только конкретные задачи:
а) меняются
б) бывают поняты неправильно
Построение же иерархий наследования предполагает, что в некий момент времени у тебя есть абсолютное и окончательное знание о том, как все должно быть. А это часто не так. Я бы даже сказал — это практически всегда не так.
Вот и получается, что сначала отнаследовали IPet от IAnimal, а потом, когда возникла необходимость, стали навешивать сверху всяческие IFish, IBird и пр.
Здравствуйте, AndrewVK, Вы писали:
AVK>Здравствуйте, AlexRK, Вы писали:
ARK>>Ну если брать язык без наследования интерфейсов, то такая запись означает, что Get() НЕ возвращает IAnimal в принципе и не реализует его методы.
AVK>Это все понятно. Но делать то что?
Василий уже ответил за меня: метод Get из third-party либы должен возвращать IAnimal + IPet, а не просто IPet.
ARK>> Аналогичная ситуация в C# — интерфейс IPet просто не отнаследован от IAnimal. Тут касти — не касти, ничего не сделаешь.
AVK>И это будет трактоваться как ошибка.
В первом случае это тоже будет ошибка. Ошибка реализации метода Get. Он не соответствует спецификации, требующей возврата двух интерфейсов. Ну так можно и пару параметров забыть.
ARK>>Кстати, еще момент. Мне не очень нравится ситуация, когда метод возвращает "не знамо что" — интерфейс, за которым непонятно какой класс.
AVK>Это называется абстракция. Предлагаешь и ее отменить?
ИМХО, не все абстракции одинаково полезны.
ARK>> ИМХО, код верхнего уровня всегда должен знать конкретные типы (должно быть — "T Get()", где T — генерик-параметр класса, реализующий IPet).
AVK>Т.е. возможность создания плагинов и аналогичных механизмов хороним в зародыше?
Нет, не хороним (Ada ведь пока существует? ). Просто код, который использует плагины, сам должен быть генерик-кодом.
Здравствуйте, AlexRK, Вы писали:
ARK>Василий уже ответил за меня: метод Get из third-party либы должен возвращать IAnimal + IPet, а не просто IPet.
Никому он ничего не должен. Констрейнтов явных нет — значит как повезет.
ARK>>>Кстати, еще момент. Мне не очень нравится ситуация, когда метод возвращает "не знамо что" — интерфейс, за которым непонятно какой класс. AVK>>Это называется абстракция. Предлагаешь и ее отменить? ARK>ИМХО, не все абстракции одинаково полезны.
Какие средства абстрагирования ты предлагаешь взамен?
AVK>>Т.е. возможность создания плагинов и аналогичных механизмов хороним в зародыше? ARK>Нет, не хороним
Хороним, потому что они все построены на том, что есть well known абстрактный контракт, и плагины его реализуют.
ARK> Просто код, который использует плагины, сам должен быть генерик-кодом.
Да хоть 10 раз, проблемы это не решает. Код хоста принципиально не может знать, какая реализация будет у абстрактного контракта в конкретном плагине.
... << RSDN@Home 1.2.0 alpha 5 rev. 52 on Windows 7 6.1.7601.65536>>
Здравствуйте, Воронков Василий, Вы писали:
ВВ>Вопрос в общем-то остается прежним — зачем *заставлять* так делать? В реальности, это единственный вопрос, на который и нужно ответить в рамках этой темы.
Затем же, зачем заставлять в статически типизированных языках контролировать соответствие типов. Наследование интерфейсов — неотъемлемая часть контракта. Если я хочу, чтобы любая реализация IPet реализовывала IAnimal (по семантике, проект у меня такой), то я хочу чтобы компилятор это жестко контролировал.
ВВ>К тому же все эти примеры с GetPet/GetItems немного странные. Либо это вообще неполиморфные функции, и тогда они должны возвращать конкретный класс
Абстракции, видишь ли, бывают многоуровневыми. И GetPet таки полиморфен (реализаций IPet может быть много), просто IAnimal это абстракция уровнем выше. Странно другое — что вы почему то уверены, что достаточно ровно два уровня абстракции на все случаи жизни — одноуровневые интерфейсы и один уровень реализации.
ВВ>, а не интерфейс, либо они являются членами, скажем, генерик-класса, и тогда они тем более не будут возвращать интерфейс, а скорее некое T, на которое будут навешаны констрейнты.
Да дались вам эти дженерики. Они ничего принципиально не меняют. Дженерики это статический полиморфизм (детали его реализации в дотнете несущественны), а наследование — динамический. Они в общем случае не взаимозаменяемы. И именно из-за попытки заменить одно другим появляются идеи вроде:
Мне не очень нравится ситуация, когда метод возвращает "не знамо что" — интерфейс, за которым непонятно какой класс. ИМХО, код верхнего уровня всегда должен знать конкретные типы ...
Вы уж либо крестик снимите, либо трусы оденьте. Либо отказ от динамического полиморфизма полностью, либо он таки есть, неважно как реализован, наследованием/реализацией интерфейсов, или исчислением каких нибудь кортежей типов интерфейсов.
... << RSDN@Home 1.2.0 alpha 5 rev. 52 on Windows 7 6.1.7601.65536>>
Здравствуйте, Воронков Василий, Вы писали:
ВВ>Построение же иерархий наследования предполагает, что в некий момент времени у тебя есть абсолютное и окончательное знание о том, как все должно быть.
Нет, не предполагает. Рефакторинг никто не отменял. И вопросы, вобщем то, совершенно параллельны конкретно наследованию, и больше относятся к статической типизации в целом.
... << RSDN@Home 1.2.0 alpha 5 rev. 52 on Windows 7 6.1.7601.65536>>
Здравствуйте, AlexRK, Вы писали:
ARK>Василий уже ответил за меня: метод Get из third-party либы должен возвращать IAnimal + IPet, а не просто IPet.
Скорее всего на практике это будет так:
Метод вернет IPet и все довольны, кроме тех кому этот IPetOnly мозолит глаза, т.к. нигде один не используется — только в связке с IAnimal.
Это все равно, что IList<T> разбить на IReadOnlyList<T> и IChangeOnlyList<T>